Skip to content

Empty bitstream file? #105

@sclsj

Description

@sclsj

Tried on several test files but wasn't able to get useful information out of the bitstream file. Examples attached:

_ext_ren_oam_md.bs.zip

Last login: Thu Aug  7 21:52:09 on ttys047
Welcome to fish, the friendly interactive shell
jin@Joy-MBP ~> goa_parse /Users/jin/libmpegh/1_ext_ren_oam_md.bs
Frame 0:
  frame_length_code: 16  (nominal_samples=1024)
  audio_truncation: 0  (0=none,1=left,2=right)
  num_samples: 1024
  objects: 10
  Object[0]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 1
    group_priority: 7
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[1]:
    element_id: 1
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[2]:
    element_id: 2
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[3]:
    element_id: 3
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[4]:
    element_id: 4
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[5]:
    element_id: 5
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[6]:
    element_id: 6
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[7]:
    element_id: 7
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[8]:
    element_id: 8
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[9]:
    element_id: 9
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  extensions: 0
jin@Joy-MBP ~> goa_parse /Users/jin/libmpegh/2_ext_ren_oam_md.bs
Frame 0:
  frame_length_code: 16  (nominal_samples=1024)
  audio_truncation: 0  (0=none,1=left,2=right)
  num_samples: 1024
  objects: 13
  Object[0]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 1
    group_priority: 7
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[1]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[2]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[3]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[4]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[5]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[6]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[7]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[8]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[9]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[10]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[11]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  Object[12]:
    element_id: 0
    has_dynamic_priority: 1
    has_uniform_spread: 0
    oam_frames: 1
      OAM[0]: present=0
    fixed_position_flag: 0
    group_priority: 0
    diffuseness: 0.000
    divergence: 0.000
    divergence_az_range: 0.00°
    exclusion_sectors: 0
  extensions: 0
jin@Joy-MBP ~> 

goa_parse, written by chatgpt

// goa_parse.c
// Parser for mpegh3da_getObjectAudioAndMetadata() object-output interface
// ISO/IEC 23008-3:2022 §17.10.3.2–3 (Tables 269–271)  [build: cc -O2 -std=c99 goa_parse.c -lm -o goa_parse]
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

typedef struct {
    const uint8_t *buf;
    size_t size_bytes;
    size_t bitpos;         // bit index into buf (for packed mode)
    int word32_mode;       // if 1: read one 32-bit word per field, MSB-aligned
    size_t word_index;     // index of 32-bit words consumed (word32 mode)
} BR;

static uint32_t read_bits_packed(BR *br, int nbits) {
    uint32_t v = 0;
    for (int i = 0; i < nbits; i++) {
        size_t byte_off = br->bitpos >> 3;
        int bit_off = 7 - (int)(br->bitpos & 7);
        if (byte_off >= br->size_bytes) {
            fprintf(stderr, "ERROR: bitstream overread in packed mode\n");
            exit(2);
        }
        v = (v << 1) | ((br->buf[byte_off] >> bit_off) & 1);
        br->bitpos++;
    }
    return v;
}

static uint32_t read_bits_word32(BR *br, int nbits) {
    // Expect each field in its own 32-bit BE word, MSB-aligned.
    size_t byte_off = br->word_index * 4;
    if (byte_off + 4 > br->size_bytes) {
        fprintf(stderr, "ERROR: bitstream overread in word32 mode\n");
        exit(2);
    }
    uint32_t w = (br->buf[byte_off+0] << 24) |
                 (br->buf[byte_off+1] << 16) |
                 (br->buf[byte_off+2] <<  8) |
                 (br->buf[byte_off+3] <<  0);
    br->word_index++;
    // Take the top nbits
    if (nbits == 32) return w;
    return (nbits == 0) ? 0 : (w >> (32 - nbits)) & ((1u << nbits) - 1u);
}

static uint32_t rb(BR *br, int nbits) {
    return br->word32_mode ? read_bits_word32(br, nbits) : read_bits_packed(br, nbits);
}

static void skip_bits(BR *br, int nbits) { (void)rb(br, nbits); }

static void print_indent(int n) { while (n--) fputs("  ", stdout); }

static void parse_one_goa_frame(BR *br, int frame_idx) {
    // ---- FRAME CONFIGURATION ----
    int goa_frameLength      = (int)rb(br, 6);
    int goa_audioTruncation  = (int)rb(br, 2);
    int goa_numSamples;
    if (goa_audioTruncation > 0) {
        goa_numSamples = (int)rb(br, 13);
    } else {
        goa_numSamples = (goa_frameLength << 6);
    }

    printf("Frame %d:\n", frame_idx);
    print_indent(1); printf("frame_length_code: %d  (nominal_samples=%d)\n",
                            goa_frameLength, (goa_frameLength << 6)); // :contentReference[oaicite:0]{index=0}
    print_indent(1); printf("audio_truncation: %d  (0=none,1=left,2=right)\n", goa_audioTruncation); // :contentReference[oaicite:1]{index=1}
    print_indent(1); printf("num_samples: %d\n", goa_numSamples); // :contentReference[oaicite:2]{index=2}

    // ---- OBJECT METADATA ----
    int goa_numberOfOutputObjects = (int)rb(br, 9);
    print_indent(1); printf("objects: %d\n", goa_numberOfOutputObjects); // :contentReference[oaicite:3]{index=3}

    for (int o = 0; o < goa_numberOfOutputObjects; o++) {
        print_indent(1); printf("Object[%d]:\n", o);
        int goa_elementID             = (int)rb(br, 9);
        int goa_hasDynamicPriority    = (int)rb(br, 1);
        int goa_hasUniformSpread      = (int)rb(br, 1);
        print_indent(2); printf("element_id: %d\n", goa_elementID);                     // :contentReference[oaicite:4]{index=4}
        print_indent(2); printf("has_dynamic_priority: %d\n", goa_hasDynamicPriority);   // :contentReference[oaicite:5]{index=5}
        print_indent(2); printf("has_uniform_spread: %d\n", goa_hasUniformSpread);       // :contentReference[oaicite:6]{index=6}

        int goa_numOAMframes = (int)rb(br, 6);
        print_indent(2); printf("oam_frames: %d\n", goa_numOAMframes);                   // :contentReference[oaicite:7]{index=7}
        for (int nf = 0; nf < goa_numOAMframes; nf++) {
            int metaPresent = (int)rb(br, 1);
            print_indent(3); printf("OAM[%d]: present=%d\n", nf, metaPresent);           // :contentReference[oaicite:8]{index=8}
            if (metaPresent) {
                int az = (int)rb(br, 8);
                int el = (int)rb(br, 6);
                int rad = (int)rb(br, 4);
                int gain = (int)rb(br, 7);

                double az_deg   = fmin(fmax((az - 128) * 1.5, -180.0), 180.0);           // :contentReference[oaicite:9]{index=9}
                double el_deg   = fmin(fmax((el - 32)  * 3.0,  -90.0),  90.0);            // :contentReference[oaicite:10]{index=10}
                double radius   = fmin(fmax(pow(2.0, (rad/3.0)) / 2.0, 0.5), 16.0);       // :contentReference[oaicite:11]{index=11}
                double gain_lin = fmin(fmax(pow(10.0, (gain - 96.0)/40.0), 0.004), 5.957);// :contentReference[oaicite:12]{index=12}

                print_indent(4); printf("pos: azimuth=%.2f° elevation=%.2f° radius=%.3f\n", az_deg, el_deg, radius);
                print_indent(4); printf("gain: %.4f\n", gain_lin);                        // :contentReference[oaicite:13]{index=13}

                if (goa_hasDynamicPriority) {
                    int dynPrio = (int)rb(br, 3);
                    print_indent(4); printf("dynamic_priority: %d\n", dynPrio);          // :contentReference[oaicite:14]{index=14}
                }

                if (goa_hasUniformSpread) {
                    int spread = (int)rb(br, 7);
                    double spread_deg = fmin(fmax(spread * 1.5, 0.0), 180.0);            // :contentReference[oaicite:15]{index=15}
                    print_indent(4); printf("spread_uniform: %.2f°\n", spread_deg);
                } else {
                    int sw = (int)rb(br, 7);
                    int sh = (int)rb(br, 5);
                    int sd = (int)rb(br, 4);
                    double sw_deg = fmin(fmax(sw * 1.5, 0.0), 180.0);                    // :contentReference[oaicite:16]{index=16}
                    double sh_deg = fmin(fmax(sh * 3.0, 0.0), 90.0);                      // :contentReference[oaicite:17]{index=17}
                    double sd_val = fmin(fmax(pow(2.0, (sd/3.0))/2.0 - 0.5, 0.0), 15.5);  // :contentReference[oaicite:18]{index=18}
                    print_indent(4); printf("spread_nonuniform: width=%.2f° height=%.2f° depth=%.2f\n",
                                            sw_deg, sh_deg, sd_val);
                }
            }
        }

        int fixedPosition = (int)rb(br, 1);
        int groupPriority = (int)rb(br, 3);
        print_indent(2); printf("fixed_position_flag: %d\n", fixedPosition);             // :contentReference[oaicite:19]{index=19}
        print_indent(2); printf("group_priority: %d\n", groupPriority);                   // :contentReference[oaicite:20]{index=20}

        int diffuseness = (int)rb(br, 7);
        int divergence  = (int)rb(br, 7);
        int divAzRange  = (int)rb(br, 6);
        print_indent(2); printf("diffuseness: %.3f\n",  diffuseness / 127.0);             // :contentReference[oaicite:21]{index=21}
        print_indent(2); printf("divergence: %.3f\n",   divergence / 127.0);              // :contentReference[oaicite:22]{index=22}
        print_indent(2); printf("divergence_az_range: %.2f°\n", divAzRange * 3.0);        // :contentReference[oaicite:23]{index=23}

        int numExcl = (int)rb(br, 4);
        print_indent(2); printf("exclusion_sectors: %d\n", numExcl);                      // :contentReference[oaicite:24]{index=24}
        for (int s = 0; s < numExcl; s++) {
            int usePredef = (int)rb(br, 1);
            if (usePredef) {
                int idx = (int)rb(br, 4);
                print_indent(3); printf("sector[%d]: predefined index=%d\n", s, idx);    // :contentReference[oaicite:25]{index=25}
            } else {
                int minAz = (int)rb(br, 7);
                int maxAz = (int)rb(br, 7);
                int minEl = (int)rb(br, 5);
                int maxEl = (int)rb(br, 5);
                double minAzDeg = fmin(fmax(3.0 * (minAz - 63), -180.0), 180.0);          // :contentReference[oaicite:26]{index=26}
                double maxAzDeg = fmin(fmax(3.0 * (maxAz - 63), -180.0), 180.0);          // :contentReference[oaicite:27]{index=27}
                double minElDeg = fmin(fmax(6.0 * (minEl - 15), -90.0), 90.0);            // :contentReference[oaicite:28]{index=28}
                double maxElDeg = fmin(fmax(6.0 * (maxEl - 15), -90.0), 90.0);            // :contentReference[oaicite:29]{index=29}
                print_indent(3); printf("sector[%d]: az=[%.1f, %.1f]° el=[%.1f, %.1f]°\n",
                                        s, minAzDeg, maxAzDeg, minElDeg, maxElDeg);
            }
        }
    }

    // ---- GOA EXTENSION ELEMENTS ----
    int numExt = (int)rb(br, 3);
    print_indent(1); printf("extensions: %d\n", numExt);                                  // :contentReference[oaicite:30]{index=30}
    for (int e = 0; e < numExt; e++) {
        int type   = (int)rb(br, 3);
        int length = (int)rb(br, 10);
        print_indent(2); printf("ext[%d]: type=%d length_bits=%d\n", e, type, length);   // :contentReference[oaicite:31]{index=31}
        if (type == 0) { // ID_EXT_GOA_PROD_METADATA
            int hasObjDist = (int)rb(br, 1);
            print_indent(3); printf("ProductionMetadata: hasObjectDistance=%d\n", hasObjDist); // :contentReference[oaicite:32]{index=32}
            if (hasObjDist) {
                for (int o = 0; o < goa_numberOfOutputObjects; o++) {
                    int distCode = (int)rb(br, 9);
                    double dist = (distCode == 0) ? 0.0
                        : 0.01 * pow(2.0, 0.0472188798661443 * (distCode - 1));         // :contentReference[oaicite:33]{index=33}
                    print_indent(4); printf("object[%d].distance = %.3f m (code=%d)\n", o, dist, distCode);
                }
            }
            // If there are remaining padding bits inside this extension, skip them:
            // We consumed 1 + 9*objects bits; if less than 'length', skip the rest.
            // (Safe no-op for packed streams that already include just the fields.)
        } else {
            // Unknown extension: skip payload bits
            skip_bits(br, length);
        }
    }
}

int main(int argc, char **argv) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <.bs file> [--word32] [--frames N]\n", argv[0]);
        return 1;
    }
    const char *path = argv[1];
    int word32 = 0;
    int frames = 1; // try one frame by default; increase if your dump concatenates frames
    for (int i = 2; i < argc; i++) {
        if (!strcmp(argv[i], "--word32")) word32 = 1;
        else if (!strcmp(argv[i], "--frames") && i+1 < argc) { frames = atoi(argv[++i]); }
    }

    FILE *f = fopen(path, "rb");
    if (!f) { perror("fopen"); return 1; }
    fseek(f, 0, SEEK_END);
    long sz = ftell(f);
    fseek(f, 0, SEEK_SET);
    if (sz <= 0) { fprintf(stderr, "ERROR: empty file\n"); fclose(f); return 1; }
    uint8_t *buf = (uint8_t*)malloc(sz);
    if (!buf) { fprintf(stderr, "OOM\n"); fclose(f); return 1; }
    if (fread(buf, 1, sz, f) != (size_t)sz) { fprintf(stderr, "ERROR: fread\n"); free(buf); fclose(f); return 1; }
    fclose(f);

    BR br = { .buf = buf, .size_bytes = (size_t)sz, .bitpos = 0, .word32_mode = word32, .word_index = 0 };

    for (int i = 0; i < frames; i++) {
        parse_one_goa_frame(&br, i);
        // If your dump includes multiple frames packed back-to-back, set --frames accordingly.
        // For "word32" dumps that repeat a pattern, increase --frames to walk through.
    }

    free(buf);
    return 0;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions