/*----------------------------------------------------------------------
|   AP4_CompactingProcessor::TrackHandler::ProcessTrack
+---------------------------------------------------------------------*/
AP4_Result
AP4_CompactingProcessor::TrackHandler::ProcessTrack()
{
    // find the stsz atom
    AP4_ContainerAtom* stbl = AP4_DYNAMIC_CAST(AP4_ContainerAtom, m_TrakAtom->FindChild("mdia/minf/stbl"));
    if (stbl == NULL) return AP4_SUCCESS;
    AP4_StszAtom* stsz = AP4_DYNAMIC_CAST(AP4_StszAtom, stbl->GetChild(AP4_ATOM_TYPE_STSZ));
    if (stsz == NULL) return AP4_SUCCESS;
    
    // check if we can reduce the size of stsz by changing it to stz2
    AP4_UI32 max_size = 0;
    for (unsigned int i=1; i<=stsz->GetSampleCount(); i++) {
        AP4_Size sample_size;
        stsz->GetSampleSize(i, sample_size);
        if (sample_size > max_size) {
            max_size = sample_size;
        }
    }
    AP4_UI08 field_size = 0;
    if (max_size <= 0xFF) {
        field_size = 1;
    } else if (max_size <= 0xFFFF) {
        field_size = 2;
    }
    if (m_Outer.m_Verbose) printf("Track %d: ", m_TrakAtom->GetId());
    if (field_size == 0) {
        if (m_Outer.m_Verbose) {
            printf("no stz2 reduction possible\n");
        }
        return AP4_SUCCESS;
    } else {
        if (m_Outer.m_Verbose) {
            unsigned int reduction = (4-field_size)*stsz->GetSampleCount();
            printf("stz2 reduction = %d bytes\n", reduction);
            m_Outer.m_SizeReduction += reduction;
        }
    }
    
    // detach the original stsz atom so we can destroy it later
    m_StszAtom = stsz;
    stsz->Detach();
    
    // create an stz2 atom and populate its entries
    AP4_Stz2Atom* stz2 = new AP4_Stz2Atom(field_size);
    for (unsigned int i=1; i<=m_StszAtom->GetSampleCount(); i++) {
        AP4_Size sample_size;
        m_StszAtom->GetSampleSize(i, sample_size);
        stz2->AddEntry(sample_size);
    }
    stbl->AddChild(stz2);
    
    return AP4_SUCCESS;
}
Exemple #2
0
/*----------------------------------------------------------------------
|   AP4_SampleTable::GenerateStblAtom
+---------------------------------------------------------------------*/
AP4_Result 
AP4_SampleTable::GenerateStblAtom(AP4_ContainerAtom*& stbl)
{
    // create the stbl container
    stbl = new AP4_ContainerAtom(AP4_ATOM_TYPE_STBL);

    // create the stsd atom
    AP4_StsdAtom* stsd = new AP4_StsdAtom(this);

    // create the stsz atom
    AP4_StszAtom* stsz = new AP4_StszAtom();

    // create the stsc atom
    AP4_StscAtom* stsc = new AP4_StscAtom();

    // create the stts atom
    AP4_SttsAtom* stts = new AP4_SttsAtom();

    // create the stss atom
    AP4_StssAtom* stss = new AP4_StssAtom();
    
    // declare the ctts atom (may be created later)
    AP4_CttsAtom* ctts = NULL;
    
    // start chunk table
    AP4_Ordinal             current_chunk_index              = 0;
    AP4_Size                current_chunk_size               = 0;
    AP4_Position            current_chunk_offset             = 0;
    AP4_Cardinal            current_samples_in_chunk         = 0;
    AP4_Ordinal             current_sample_description_index = 0;
    AP4_UI32                current_duration                 = 0;
    AP4_Cardinal            current_duration_run             = 0;
    AP4_UI32                current_cts_delta                = 0;
    AP4_Cardinal            current_cts_delta_run            = 0;
    AP4_Array<AP4_Position> chunk_offsets;

    // process all the samples
    bool         all_samples_are_sync = false;
    AP4_Cardinal sample_count = GetSampleCount();
    for (AP4_Ordinal i=0; i<sample_count; i++) {
        AP4_Sample sample;
        GetSample(i, sample);
        
        // update DTS table
        AP4_UI32 new_duration = sample.GetDuration();
        if (new_duration != current_duration && current_duration_run != 0) {
            // emit a new stts entry
            stts->AddEntry(current_duration_run, current_duration);
            
            // reset the run count
            current_duration_run = 0;
        } 
        ++current_duration_run;
        current_duration = new_duration;
        
        // update CTS table
        AP4_UI32 new_cts_delta = sample.GetCtsDelta();
        if (new_cts_delta != current_cts_delta && current_cts_delta_run != 0) {
            // create a ctts atom if we don't have one
            if (ctts == NULL) ctts = new AP4_CttsAtom();
            
            //emit a new ctts entry
            ctts->AddEntry(current_cts_delta_run, current_cts_delta);
            
            // reset the run count
            current_cts_delta_run = 0;
        }
        ++current_cts_delta_run;
        current_cts_delta = new_cts_delta;
        
        // add an entry into the stsz atom
        stsz->AddEntry(sample.GetSize());
        
        // update the sync sample table
        if (sample.IsSync()) {
            stss->AddEntry(i+1);
            if (i==0) all_samples_are_sync = true;
        } else {
            all_samples_are_sync = false;
        }
        
        // see in which chunk this sample is
        AP4_Ordinal chunk_index = 0;
        AP4_Ordinal position_in_chunk = 0;
        AP4_Result  result = GetSampleChunkPosition(i, chunk_index, position_in_chunk);
        if (AP4_SUCCEEDED(result)) {
            if (chunk_index != current_chunk_index && current_samples_in_chunk != 0) {
                // new chunk
                chunk_offsets.Append(current_chunk_offset);
                current_chunk_offset += current_chunk_size;

                stsc->AddEntry(1, 
                               current_samples_in_chunk,
                               current_sample_description_index+1);

                current_samples_in_chunk = 0;
                current_chunk_size       = 0;
            }
            current_chunk_index = chunk_index;
        }

        // store the sample description index
        current_sample_description_index = sample.GetDescriptionIndex();
                
        // adjust the current chunk info
        current_chunk_size += sample.GetSize();
        ++current_samples_in_chunk;        
    }

    // finish the stts table
    if (sample_count) stts->AddEntry(current_duration_run, current_duration);

    // finish the ctts table if we have one
    if (ctts) {
        AP4_ASSERT(current_cts_delta_run != 0);
        
        // add a ctts entry
        ctts->AddEntry(current_cts_delta_run, current_cts_delta);
    } 
    
    // process any unfinished chunk
    if (current_samples_in_chunk != 0) {
        // new chunk
        chunk_offsets.Append(current_chunk_offset);
        stsc->AddEntry(1, 
                       current_samples_in_chunk,
                       current_sample_description_index+1);
    }

    // attach the children of stbl
    stbl->AddChild(stsd);
    stbl->AddChild(stsz);
    stbl->AddChild(stsc);
    stbl->AddChild(stts);
    if (ctts) stbl->AddChild(ctts);
    if (!all_samples_are_sync && stss->GetEntries().ItemCount() != 0) {
        stbl->AddChild(stss);
    } else {
        delete stss;
    }
    
    // see if we need a co64 or an stco atom
    AP4_Size  chunk_count = chunk_offsets.ItemCount();
    if (current_chunk_offset <= 0xFFFFFFFF) {
        // make an array of 32-bit entries
        AP4_UI32* chunk_offsets_32 = new AP4_UI32[chunk_count];
        for (unsigned int i=0; i<chunk_count; i++) {
            chunk_offsets_32[i] = (AP4_UI32)chunk_offsets[i];
        }
        // create the stco atom
        AP4_StcoAtom* stco = new AP4_StcoAtom(&chunk_offsets_32[0], chunk_count);
        stbl->AddChild(stco);

        delete[] chunk_offsets_32;
    } else {
        // create the co64 atom
        AP4_Co64Atom* co64 = new AP4_Co64Atom(&chunk_offsets[0], chunk_count);
        stbl->AddChild(co64);
    }


    return AP4_SUCCESS;
}
Exemple #3
0
/*----------------------------------------------------------------------
|       AP4_SampleTable::GenerateStblAtom
+---------------------------------------------------------------------*/
AP4_Result 
AP4_SampleTable::GenerateStblAtom(AP4_ContainerAtom*& stbl)
{
    // create the stbl container
    stbl = DNew AP4_ContainerAtom(AP4_ATOM_TYPE_STBL);

    // create the stsd atom
    AP4_StsdAtom* stsd = DNew AP4_StsdAtom(this);

    // create the stsz atom
    AP4_StszAtom* stsz = DNew AP4_StszAtom();

    // create the stsc atom
    AP4_StscAtom* stsc = DNew AP4_StscAtom();

    // start chunk table
    AP4_Cardinal        samples_in_chunk = 0;
    AP4_Offset          current_chunk_offset = 0;
    AP4_Size            current_chunk_size = 0;
    AP4_Array<AP4_UI32> chunk_offsets;

    // process all the samples
    AP4_Cardinal sample_count = GetSampleCount();
    for (AP4_Ordinal i=0; i<sample_count; i++) {
        AP4_Sample sample;
        GetSample(i, sample);
        
        // add an entry into the stsz atom
        stsz->AddEntry(sample.GetSize());
        
        // adjust the current chunk info
        current_chunk_size += sample.GetSize();

        // count the sample
        samples_in_chunk++;
        if (samples_in_chunk == 10) {
            // new chunk
            chunk_offsets.Append(current_chunk_offset);
            stsc->AddEntry(1, 10, 1);
            samples_in_chunk = 0;

            // adjust the chunk offset
            current_chunk_offset += current_chunk_size;
            current_chunk_size = 0;
        }
    }

    // process any unfinished chunk
    if (samples_in_chunk != 0) {
        // new chunk
        chunk_offsets.Append(current_chunk_offset);
        stsc->AddEntry(1, samples_in_chunk, 1);
    }

    // create the stco atom
    AP4_StcoAtom* stco = DNew AP4_StcoAtom(&chunk_offsets[0], 
                                          chunk_offsets.ItemCount());

    // create the stts atom (for now, we assume sample of equal duration)
    AP4_SttsAtom* stts = DNew AP4_SttsAtom();
    stts->AddEntry(sample_count, 1000); // FIXME

    // attach the children of stbl
    stbl->AddChild(stsd);
    stbl->AddChild(stsz);
    stbl->AddChild(stsc);
    stbl->AddChild(stco);
    stbl->AddChild(stts);

    return AP4_SUCCESS;
}