Ejemplo n.º 1
0
void MP4Track::FinishWrite()
{
	// write out any remaining samples in chunk buffer
	WriteChunkBuffer();

	// record buffer size and bitrates
	MP4BitfieldProperty* pBufferSizeProperty;

	if (m_pTrakAtom->FindProperty(
	  "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.bufferSizeDB",
	  (MP4Property**)&pBufferSizeProperty)) {
		pBufferSizeProperty->SetValue(GetMaxSampleSize());
	}

	MP4Integer32Property* pBitrateProperty;

	if (m_pTrakAtom->FindProperty(
	  "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.maxBitrate",
	  (MP4Property**)&pBitrateProperty)) {
		pBitrateProperty->SetValue(GetMaxBitrate());
	}

	if (m_pTrakAtom->FindProperty(
	  "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.avgBitrate",
	  (MP4Property**)&pBitrateProperty)) {
		pBitrateProperty->SetValue(GetAvgBitrate());
	}
}
Ejemplo n.º 2
0
void MP4File::CreateIsmaODUpdateCommandForStream(
    MP4DescriptorProperty* pAudioEsdProperty,
    MP4DescriptorProperty* pVideoEsdProperty,
    u_int8_t** ppBytes,
    u_int64_t* pNumBytes)
{
    MP4Descriptor* pAudioOd = NULL;
    MP4Descriptor* pVideoOd = NULL;

    MP4Descriptor* pCommand =
        CreateODCommand(MP4ODUpdateODCommandTag);
    pCommand->Generate();

    for (u_int8_t i = 0; i < 2; i++) {
        u_int16_t odId;
        MP4DescriptorProperty* pEsdProperty = NULL;

        if (i == 0) {
            odId = 10;
            pEsdProperty = pAudioEsdProperty;
        } else {
            odId = 20;
            pEsdProperty = pVideoEsdProperty;
        }

        if (pEsdProperty == NULL) {
            continue;
        }

        MP4DescriptorProperty* pOdDescrProperty =
            (MP4DescriptorProperty*)(pCommand->GetProperty(0));

        pOdDescrProperty->SetTags(MP4ODescrTag);

        MP4Descriptor* pOd =
            pOdDescrProperty->AddDescriptor(MP4ODescrTag);
        pOd->Generate();

        if (i == 0) {
            pAudioOd = pOd;
        } else {
            pVideoOd = pOd;
        }

        MP4BitfieldProperty* pOdIdProperty = NULL;
        pOd->FindProperty("objectDescriptorId",
                          (MP4Property**)&pOdIdProperty);
        pOdIdProperty->SetValue(odId);

        delete (MP4DescriptorProperty*)pOd->GetProperty(4);
        pOd->SetProperty(4, pEsdProperty);
    }

    // serialize OD command
    pCommand->WriteToMemory(this, ppBytes, pNumBytes);

    // detach from esd descriptor params
    if (pAudioOd) {
        pAudioOd->SetProperty(4, NULL);
    }
    if (pVideoOd) {
        pVideoOd->SetProperty(4, NULL);
    }

    // then destroy
    delete pCommand;
}
Ejemplo n.º 3
0
void MP4File::CreateIsmaODUpdateCommandFromFileForStream(
    MP4TrackId audioTrackId,
    MP4TrackId videoTrackId,
    u_int8_t** ppBytes,
    u_int64_t* pNumBytes)
{
    MP4DescriptorProperty* pAudioEsd = NULL;
    MP4Integer8Property* pAudioSLConfigPredef = NULL;
    MP4BitfieldProperty* pAudioAccessUnitEndFlag = NULL;
    int oldAudioUnitEndFlagValue = 0;
    MP4DescriptorProperty* pVideoEsd = NULL;
    MP4Integer8Property* pVideoSLConfigPredef = NULL;
    MP4BitfieldProperty* pVideoAccessUnitEndFlag = NULL;
    int oldVideoUnitEndFlagValue = 0;
    MP4IntegerProperty* pAudioEsdId = NULL;
    MP4IntegerProperty* pVideoEsdId = NULL;

    if (audioTrackId != MP4_INVALID_TRACK_ID) {
        // changed mp4a to * to handle enca case
        MP4Atom* pEsdsAtom =
            FindAtom(MakeTrackName(audioTrackId,
                                   "mdia.minf.stbl.stsd.*.esds"));
        ASSERT(pEsdsAtom);

        pAudioEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2));
        // ESID is 0 for file, stream needs to be non-ze
        pAudioEsd->FindProperty("ESID",
                                (MP4Property**)&pAudioEsdId);

        ASSERT(pAudioEsdId);
        pAudioEsdId->SetValue(audioTrackId);

        // SL config needs to change from 2 (file) to 1 (null)
        pAudioEsd->FindProperty("slConfigDescr.predefined",
                                (MP4Property**)&pAudioSLConfigPredef);
        ASSERT(pAudioSLConfigPredef);
        pAudioSLConfigPredef->SetValue(0);

        pAudioEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag",
                                (MP4Property **)&pAudioAccessUnitEndFlag);
        oldAudioUnitEndFlagValue =
            pAudioAccessUnitEndFlag->GetValue();
        pAudioAccessUnitEndFlag->SetValue(1);
    }

    if (videoTrackId != MP4_INVALID_TRACK_ID) {
        // changed mp4v to * to handle encv case
        MP4Atom* pEsdsAtom =
            FindAtom(MakeTrackName(videoTrackId,
                                   "mdia.minf.stbl.stsd.*.esds"));
        ASSERT(pEsdsAtom);

        pVideoEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2));
        pVideoEsd->FindProperty("ESID",
                                (MP4Property**)&pVideoEsdId);

        ASSERT(pVideoEsdId);
        pVideoEsdId->SetValue(videoTrackId);

        // SL config needs to change from 2 (file) to 1 (null)
        pVideoEsd->FindProperty("slConfigDescr.predefined",
                                (MP4Property**)&pVideoSLConfigPredef);
        ASSERT(pVideoSLConfigPredef);
        pVideoSLConfigPredef->SetValue(0);

        pVideoEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag",
                                (MP4Property **)&pVideoAccessUnitEndFlag);
        oldVideoUnitEndFlagValue =
            pVideoAccessUnitEndFlag->GetValue();
        pVideoAccessUnitEndFlag->SetValue(1);
    }

    CreateIsmaODUpdateCommandForStream(
        pAudioEsd, pVideoEsd, ppBytes, pNumBytes);
    VERBOSE_ISMA(GetVerbosity(),
                 printf("After CreateImsaODUpdateCommandForStream len %llu =\n", *pNumBytes); MP4HexDump(*ppBytes, *pNumBytes));
    // return SL config values to 2 (file)
    // return ESID values to 0
    if (pAudioSLConfigPredef) {
        pAudioSLConfigPredef->SetValue(2);
    }
    if (pAudioEsdId) {
        pAudioEsdId->SetValue(0);
    }
    if (pAudioAccessUnitEndFlag) {
        pAudioAccessUnitEndFlag->SetValue(oldAudioUnitEndFlagValue );
    }
    if (pVideoEsdId) {
        pVideoEsdId->SetValue(0);
    }
    if (pVideoSLConfigPredef) {
        pVideoSLConfigPredef->SetValue(2);
    }
    if (pVideoAccessUnitEndFlag) {
        pVideoAccessUnitEndFlag->SetValue(oldVideoUnitEndFlagValue );
    }
}
Ejemplo n.º 4
0
void MP4File::CreateIsmaODUpdateCommandFromFileForFile(
    MP4TrackId odTrackId,
    MP4TrackId audioTrackId,
    MP4TrackId videoTrackId,
    u_int8_t** ppBytes,
    u_int64_t* pNumBytes)
{
    MP4Descriptor* pCommand = CreateODCommand(MP4ODUpdateODCommandTag);
    pCommand->Generate();

    for (u_int8_t i = 0; i < 2; i++) {
        MP4TrackId trackId;
        u_int16_t odId;

        if (i == 0) {
            trackId = audioTrackId;
            odId = 10;
        } else {
            trackId = videoTrackId;
            odId = 20;
        }

        if (trackId == MP4_INVALID_TRACK_ID) {
            continue;
        }

        MP4DescriptorProperty* pOdDescrProperty =
            (MP4DescriptorProperty*)(pCommand->GetProperty(0));

        pOdDescrProperty->SetTags(MP4FileODescrTag);

        MP4Descriptor* pOd =
            pOdDescrProperty->AddDescriptor(MP4FileODescrTag);

        pOd->Generate();

        MP4BitfieldProperty* pOdIdProperty = NULL;
        pOd->FindProperty("objectDescriptorId",
                          (MP4Property**)&pOdIdProperty);
        pOdIdProperty->SetValue(odId);

        MP4DescriptorProperty* pEsIdsDescriptorProperty = NULL;
        pOd->FindProperty("esIds",
                          (MP4Property**)&pEsIdsDescriptorProperty);
        ASSERT(pEsIdsDescriptorProperty);

        pEsIdsDescriptorProperty->SetTags(MP4ESIDRefDescrTag);

        MP4Descriptor *pRefDescriptor =
            pEsIdsDescriptorProperty->AddDescriptor(MP4ESIDRefDescrTag);
        pRefDescriptor->Generate();

        MP4Integer16Property* pRefIndexProperty = NULL;
        pRefDescriptor->FindProperty("refIndex",
                                     (MP4Property**)&pRefIndexProperty);
        ASSERT(pRefIndexProperty);

        u_int32_t mpodIndex = FindTrackReference(
                                  MakeTrackName(odTrackId, "tref.mpod"), trackId);
        ASSERT(mpodIndex != 0);

        pRefIndexProperty->SetValue(mpodIndex);
    }

    pCommand->WriteToMemory(this, ppBytes, pNumBytes);

    delete pCommand;
}
Ejemplo n.º 5
0
MP4Descriptor* MP4File::CreateESD(
    MP4DescriptorProperty* pEsProperty,
    u_int32_t esid,
    u_int8_t objectType,
    u_int8_t streamType,
    u_int32_t bufferSize,
    u_int32_t bitrate,
    u_int8_t* pConfig,
    u_int32_t configLength,
    char* url)
{
    MP4IntegerProperty* pInt;
    MP4StringProperty* pString;
    MP4BytesProperty* pBytes;
    MP4BitfieldProperty* pBits;

    MP4Descriptor* pEsd =
        pEsProperty->AddDescriptor(MP4ESDescrTag);
    pEsd->Generate();

    pEsd->FindProperty("ESID",
                       (MP4Property**)&pInt);
    pInt->SetValue(esid);

    pEsd->FindProperty("decConfigDescr.objectTypeId",
                       (MP4Property**)&pInt);
    pInt->SetValue(objectType);

    pEsd->FindProperty("decConfigDescr.streamType",
                       (MP4Property**)&pInt);
    pInt->SetValue(streamType);

    pEsd->FindProperty("decConfigDescr.bufferSizeDB",
                       (MP4Property**)&pInt);
    pInt->SetValue(bufferSize);

    pEsd->FindProperty("decConfigDescr.maxBitrate",
                       (MP4Property**)&pInt);
    pInt->SetValue(bitrate);

    pEsd->FindProperty("decConfigDescr.avgBitrate",
                       (MP4Property**)&pInt);
    pInt->SetValue(bitrate);

    MP4DescriptorProperty* pConfigDescrProperty;
    pEsd->FindProperty("decConfigDescr.decSpecificInfo",
                       (MP4Property**)&pConfigDescrProperty);

    MP4Descriptor* pConfigDescr =
        pConfigDescrProperty->AddDescriptor(MP4DecSpecificDescrTag);
    pConfigDescr->Generate();

    pConfigDescrProperty->FindProperty("decSpecificInfo[0].info",
                                       (MP4Property**)&pBytes);
    pBytes->SetValue(pConfig, configLength);

    pEsd->FindProperty("slConfigDescr.predefined",
                       (MP4Property**)&pInt);
    // changed 12/5/02 from plugfest to value 0
    pInt->SetValue(0);

    pEsd->FindProperty("slConfig.useAccessUnitEndFlag",
                       (MP4Property **)&pBits);
    pBits->SetValue(1);

    if (url) {
        pEsd->FindProperty("URLFlag",
                           (MP4Property**)&pInt);
        pInt->SetValue(1);

        pEsd->FindProperty("URL",
                           (MP4Property**)&pString);
        pString->SetValue(url);
    }

    return pEsd;
}
Ejemplo n.º 6
0
void MP4File::CreateIsmaIodFromFile(
    MP4TrackId odTrackId,
    MP4TrackId sceneTrackId,
    MP4TrackId audioTrackId,
    MP4TrackId videoTrackId,
    u_int8_t** ppBytes,
    u_int64_t* pNumBytes)
{
    MP4Descriptor* pIod = new MP4IODescriptor();
    pIod->SetTag(MP4IODescrTag);
    pIod->Generate();

    MP4Atom* pIodsAtom = FindAtom("moov.iods");
    ASSERT(pIodsAtom);
    MP4DescriptorProperty* pSrcIod =
        (MP4DescriptorProperty*)pIodsAtom->GetProperty(2);

    CloneIntegerProperty(pIod, pSrcIod, "objectDescriptorId");
    CloneIntegerProperty(pIod, pSrcIod, "ODProfileLevelId");
    CloneIntegerProperty(pIod, pSrcIod, "sceneProfileLevelId");
    CloneIntegerProperty(pIod, pSrcIod, "audioProfileLevelId");
    CloneIntegerProperty(pIod, pSrcIod, "visualProfileLevelId");
    CloneIntegerProperty(pIod, pSrcIod, "graphicsProfileLevelId");

    // mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag
    MP4DescriptorProperty* pEsProperty;
    pIod->FindProperty("esIds", (MP4Property**)&pEsProperty);
    pEsProperty->SetTags(MP4ESDescrTag);

    MP4IntegerProperty* pSetProperty;
    MP4IntegerProperty* pSceneESID;
    MP4IntegerProperty* pOdESID;

    // OD
    MP4Descriptor* pOdEsd =
        pEsProperty->AddDescriptor(MP4ESDescrTag);
    pOdEsd->Generate();

    pOdEsd->FindProperty("ESID",
                         (MP4Property**)&pOdESID);

    // we set the OD ESID to a non-zero unique value
    pOdESID->SetValue(m_odTrackId);

    pOdEsd->FindProperty("URLFlag",
                         (MP4Property**)&pSetProperty);
    pSetProperty->SetValue(1);

    u_int8_t* pBytes;
    u_int64_t numBytes;

    CreateIsmaODUpdateCommandFromFileForStream(
        audioTrackId,
        videoTrackId,
        &pBytes,
        &numBytes);

    VERBOSE_ISMA(GetVerbosity(),
                 printf("OD data =\n"); MP4HexDump(pBytes, numBytes));

    char* odCmdBase64 = MP4ToBase64(pBytes, numBytes);

    char* urlBuf = (char*)MP4Malloc(strlen(odCmdBase64) + 64);

    sprintf(urlBuf,
            "data:application/mpeg4-od-au;base64,%s",
            odCmdBase64);

    MP4StringProperty* pUrlProperty;
    pOdEsd->FindProperty("URL",
                         (MP4Property**)&pUrlProperty);
    pUrlProperty->SetValue(urlBuf);

    VERBOSE_ISMA(GetVerbosity(),
                 printf("OD data URL = \042%s\042\n", urlBuf));

    MP4Free(odCmdBase64);
    odCmdBase64 = NULL;
    MP4Free(pBytes);
    pBytes = NULL;
    MP4Free(urlBuf);
    urlBuf = NULL;

    MP4DescriptorProperty* pSrcDcd = NULL;

    // HACK temporarily point to scene decoder config
    FindProperty(MakeTrackName(odTrackId,
                               "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"),
                 (MP4Property**)&pSrcDcd);
    ASSERT(pSrcDcd);
    MP4Property* pOrgOdEsdProperty =
        pOdEsd->GetProperty(8);
    pOdEsd->SetProperty(8, pSrcDcd);

    // bufferSizeDB needs to be set appropriately
    MP4BitfieldProperty* pBufferSizeProperty = NULL;
    pOdEsd->FindProperty("decConfigDescr.bufferSizeDB",
                         (MP4Property**)&pBufferSizeProperty);
    ASSERT(pBufferSizeProperty);
    pBufferSizeProperty->SetValue(numBytes);

    // SL config needs to change from 2 (file) to 1 (null)
    pOdEsd->FindProperty("slConfigDescr.predefined",
                         (MP4Property**)&pSetProperty);
    pSetProperty->SetValue(1);


    // Scene
    MP4Descriptor* pSceneEsd =
        pEsProperty->AddDescriptor(MP4ESDescrTag);
    pSceneEsd->Generate();

    pSceneEsd->FindProperty("ESID",
                            (MP4Property**)&pSceneESID);
    // we set the Scene ESID to a non-zero unique value
    pSceneESID->SetValue(sceneTrackId);

    pSceneEsd->FindProperty("URLFlag",
                            (MP4Property**)&pSetProperty);
    pSetProperty->SetValue(1);

    CreateIsmaSceneCommand(
        MP4_IS_VALID_TRACK_ID(audioTrackId),
        MP4_IS_VALID_TRACK_ID(videoTrackId),
        &pBytes,
        &numBytes);

    VERBOSE_ISMA(GetVerbosity(),
                 printf("Scene data =\n"); MP4HexDump(pBytes, numBytes));

    char *sceneCmdBase64 = MP4ToBase64(pBytes, numBytes);

    urlBuf = (char*)MP4Malloc(strlen(sceneCmdBase64) + 64);
    sprintf(urlBuf,
            "data:application/mpeg4-bifs-au;base64,%s",
            sceneCmdBase64);

    pSceneEsd->FindProperty("URL",
                            (MP4Property**)&pUrlProperty);
    pUrlProperty->SetValue(urlBuf);

    VERBOSE_ISMA(GetVerbosity(),
                 printf("Scene data URL = \042%s\042\n", urlBuf));

    MP4Free(sceneCmdBase64);
    sceneCmdBase64 = NULL;
    MP4Free(urlBuf);
    urlBuf = NULL;
    MP4Free(pBytes);
    pBytes = NULL;

    // HACK temporarily point to scene decoder config
    FindProperty(MakeTrackName(sceneTrackId,
                               "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"),
                 (MP4Property**)&pSrcDcd);
    ASSERT(pSrcDcd);
    MP4Property* pOrgSceneEsdProperty =
        pSceneEsd->GetProperty(8);
    pSceneEsd->SetProperty(8, pSrcDcd);

    // bufferSizeDB needs to be set
    pBufferSizeProperty = NULL;
    pSceneEsd->FindProperty("decConfigDescr.bufferSizeDB",
                            (MP4Property**)&pBufferSizeProperty);
    ASSERT(pBufferSizeProperty);
    pBufferSizeProperty->SetValue(numBytes);

    // SL config needs to change from 2 (file) to 1 (null)
    pSceneEsd->FindProperty("slConfigDescr.predefined",
                            (MP4Property**)&pSetProperty);
    pSetProperty->SetValue(1);


    // finally get the whole thing written to a memory
    pIod->WriteToMemory(this, ppBytes, pNumBytes);


    // now carefully replace esd properties before destroying
    pOdEsd->SetProperty(8, pOrgOdEsdProperty);
    pSceneEsd->SetProperty(8, pOrgSceneEsdProperty);
    pSceneESID->SetValue(0); // restore 0 value
    pOdESID->SetValue(0);

    delete pIod;

    VERBOSE_ISMA(GetVerbosity(),
                 printf("IOD data =\n"); MP4HexDump(*ppBytes, *pNumBytes));
}
Ejemplo n.º 7
0
/*
 * Normalling the Dump of the atom looks like the following, we want to spruce
 * this up a bit to give more information.
 *
 *      type = dac3
 *       fscod = 0 (0x0) <2 bits>
 *       bsid = 8 (0x08) <5 bits>
 *       bsmod = 0 (0x0) <3 bits>
 *       acmod = 7 (0x7) <3 bits>
 *       lfeon = 1 (0x1) <1 bits>
 *       bit_rate_code = 15 (0x0f) <5 bits>
 *       reserved = 0 (0x00) <5 bits>
 *
 * into:
 *      type = dac3
 *       fscod = 0 (0x0) <2 bits> [48 kHz]
 *       bsid = 8 (0x08) <5 bits>
 *       bsmod = 0 (0x0) <3 bits> [Main audio service: complete main (CM)]
 *       acmod = 7 (0x7) <3 bits> [3/2 (L, C, R, SL, SR)]
 *       lfeon = 1 (0x1) <1 bits> [ENABLED]
 *       bit_rate_code = 15 (0x0f) <5 bits> [448 kbit/s]
 *       reserved = 0 (0x00) <5 bits>
 *
 */
void MP4DAc3Atom::Dump(FILE* pFile, uint8_t indent, bool dumpImplicits)
{
  
    MP4BitfieldProperty* fscodProp = ((MP4BitfieldProperty*)m_pProperties[0]);
    MP4BitfieldProperty* bsidProp = ((MP4BitfieldProperty*)m_pProperties[1]);
    MP4BitfieldProperty* bsmodProp = ((MP4BitfieldProperty*)m_pProperties[2]);
    MP4BitfieldProperty* acmodProp = ((MP4BitfieldProperty*)m_pProperties[3]);
    MP4BitfieldProperty* lfeonProp = ((MP4BitfieldProperty*)m_pProperties[4]);
    MP4BitfieldProperty* brcProp = ((MP4BitfieldProperty*)m_pProperties[5]);
    MP4BitfieldProperty* resProp = ((MP4BitfieldProperty*)m_pProperties[6]);
    
    Indent(pFile, indent++);

    fprintf(pFile, "type = dac3\n");

    if (fscodProp) { 
        uint64_t fscod = 0xFF;
        const char* fscodString; 
        const char* fscods[] = {
            "48", "44.1", "32", "Reserved",
        };

        Indent(pFile, indent);

        fscod = fscodProp->GetValue();

        if (fscod < (sizeof(fscods) / sizeof(fscods[0]))) {
            fscodString = fscods[fscod];
        } else {
            fscodString = "Invalid value";
        }

        uint8_t hexWidth = fscodProp->GetNumBits() / 4;
        if (hexWidth == 0 || (fscodProp->GetNumBits() % 4)) {
            hexWidth++;
        }

        fprintf(pFile, 
                "fscod = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits> [%s kHz]\n",
                fscod, (int)hexWidth, fscod, fscodProp->GetNumBits(), fscodString);
    }
    if (bsidProp)  bsidProp->Dump(pFile, indent, dumpImplicits);

    if (bsmodProp) { 
        uint64_t bsmod = 0xFF;
        const char* bsmodString; 
        const char* bsmods[] = {
            "Main audio service: complete main (CM)",
            "Main audio srrvice: music and effects (ME)",
            "Associated service: visually impaired (VI)",
            "Associated service: hearing impaired (HI)",
            "Associated service: dialogue (D)",
            "Associated service: commentary (C)",
            "Associated service: emergency (E)",
            "Associated service: voice over (VO) or Main audio service: karaoke",
        };

        Indent(pFile, indent);

        bsmod = bsmodProp->GetValue();

        if (bsmod < (sizeof(bsmods) / sizeof(bsmods[0]))) {
            bsmodString = bsmods[bsmod];
        } else {
            bsmodString = "Invalid value";
        }

        uint8_t hexWidth = bsmodProp->GetNumBits() / 4;
        if (hexWidth == 0 || (bsmodProp->GetNumBits() % 4)) {
            hexWidth++;
        }

        fprintf(pFile, 
                "bsmod = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits> [%s]\n",
                bsmod, (int)hexWidth, bsmod, bsmodProp->GetNumBits(), bsmodString);
    }
    
    if (acmodProp) { 
        uint64_t acmod = 0xFF;
        const char* acmodString; 

        const char* acmods[] = {
            "1 + 1 (Ch1, Ch2)",
            "1/0 (C)",
            "2/0 (L, R)",
            "3/0 (L, C, R)",
            "2/1 (L, R, S)",
            "3/1 (L, C, R, S)",
            "2/2 (L, R, SL, SR)",
            "3/2 (L, C, R, SL, SR)",
        };

        Indent(pFile, indent);

        acmod = acmodProp->GetValue();

        if (acmod < (sizeof(acmods) / sizeof(acmods[0]))) {
            acmodString = acmods[acmod];
        } else {
            acmodString = "Invalid value";
        }

        uint8_t hexWidth = acmodProp->GetNumBits() / 4;
        if (hexWidth == 0 || (acmodProp->GetNumBits() % 4)) {
            hexWidth++;
        }

        fprintf(pFile, 
                "acmod = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits> [%s]\n",
                acmod, (int)hexWidth, acmod, acmodProp->GetNumBits(), acmodString);
    }

    if (lfeonProp) {
        uint64_t lfeon = lfeonProp->GetValue();
        uint8_t hexWidth = lfeonProp->GetNumBits() / 4;
        
        Indent(pFile, indent);

        if (hexWidth == 0 || (lfeonProp->GetNumBits() % 4)) {
            hexWidth++;
        }
        
        fprintf(pFile, 
                "lfeon = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits> [%s]\n",
                lfeon, (int)hexWidth, lfeon, 
                lfeonProp->GetNumBits(), lfeon ? "ENABLED" : "DISABLED"); 
    }
    
    if (brcProp) {
        uint32_t bit_rate_codes[] = {
            32,
            40, 
            48, 
            56, 
            64,
            80,
            96, 
            112, 
            128, 
            160, 
            192, 
            224, 
            256, 
            320, 
            384, 
            448, 
            512, 
            576, 
            640,
        };
        uint64_t bit_rate_code = brcProp->GetValue();
        uint32_t bit_rate;

        Indent(pFile, indent);

        if (bit_rate_code < (sizeof(bit_rate_codes) / sizeof(bit_rate_codes[0]))) {
            bit_rate = bit_rate_codes[bit_rate_code];
        } else {
            bit_rate = 0;
        }

        uint8_t hexWidth = brcProp->GetNumBits() / 4;
        if (hexWidth == 0 || (brcProp->GetNumBits() % 4)) {
            hexWidth++;
        }
        
        fprintf(pFile, 
                "bit_rate_code = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits> [%" PRIu32 " kbit/s]\n",
                bit_rate_code, (int)hexWidth, bit_rate_code, 
                brcProp->GetNumBits(), bit_rate); 
    }
    if (resProp) resProp->Dump(pFile, indent, dumpImplicits);
}