Beispiel #1
0
/*----------------------------------------------------------------------
|   AP4_StscAtom::AP4_StscAtom
+---------------------------------------------------------------------*/
AP4_StscAtom::AP4_StscAtom(AP4_UI32        size, 
                           AP4_UI32        version,
                           AP4_UI32        flags,
                           AP4_ByteStream& stream) :
    AP4_Atom(AP4_ATOM_TYPE_STSC, size, version, flags),
    m_CachedChunkGroup(0)
{
    AP4_UI32 first_sample = 1;
    AP4_UI32 entry_count;
    stream.ReadUI32(entry_count);
    m_Entries.SetItemCount(entry_count);
    unsigned char* buffer = new unsigned char[entry_count*12];
    AP4_Result result = stream.Read(buffer, entry_count*12);
    if (AP4_FAILED(result)) {
        delete[] buffer;
        return;
    }
    for (unsigned int i=0; i<entry_count; i++) {
        AP4_UI32 first_chunk              = AP4_BytesToUInt32BE(&buffer[i*12  ]);
        AP4_UI32 samples_per_chunk        = AP4_BytesToUInt32BE(&buffer[i*12+4]);
        AP4_UI32 sample_description_index = AP4_BytesToUInt32BE(&buffer[i*12+8]);
        if (i) {
            AP4_Ordinal prev = i-1;
            m_Entries[prev].m_ChunkCount = first_chunk-m_Entries[prev].m_FirstChunk;
            first_sample += m_Entries[prev].m_ChunkCount * m_Entries[prev].m_SamplesPerChunk;
        }
        m_Entries[i].m_ChunkCount             = 0; // not known yet
        m_Entries[i].m_FirstChunk             = first_chunk;
        m_Entries[i].m_FirstSample            = first_sample;
        m_Entries[i].m_SamplesPerChunk        = samples_per_chunk;
        m_Entries[i].m_SampleDescriptionIndex = sample_description_index;
    }
    delete[] buffer;
}
/*----------------------------------------------------------------------
|   AP4_StssAtom::AP4_StssAtom
+---------------------------------------------------------------------*/
AP4_StssAtom::AP4_StssAtom(AP4_UI32        size, 
                           AP4_UI08        version,
                           AP4_UI32        flags,
                           AP4_ByteStream& stream) :
    AP4_Atom(AP4_ATOM_TYPE_STSS, size, version, flags),
    m_LookupCache(0)
{
    AP4_UI32 entry_count;
    stream.ReadUI32(entry_count);
    
    // check for bogus values
    if (entry_count*4 > size) return;
    
    // read the table into a local array for conversion
    unsigned char* buffer = new unsigned char[entry_count*4];
    AP4_Result result = stream.Read(buffer, entry_count*4);
    if (AP4_FAILED(result)) {
        delete[] buffer;
        return;
    }
    m_Entries.SetItemCount(entry_count);
    for (unsigned int i=0; i<entry_count; i++) {
        m_Entries[i] = AP4_BytesToUInt32BE(&buffer[i*4]);
    }
    delete[] buffer;
}
/*----------------------------------------------------------------------
|   IsIFrame
+---------------------------------------------------------------------*/
static bool
IsIFrame(AP4_Sample& sample, AP4_AvcSampleDescription* avc_desc) {
    AP4_DataBuffer sample_data;
    if (AP4_FAILED(sample.ReadData(sample_data))) {
        return false;
    }

    const unsigned char* data = sample_data.GetData();
    AP4_Size             size = sample_data.GetDataSize();

    while (size >= avc_desc->GetNaluLengthSize()) {
        unsigned int nalu_length = 0;
        if (avc_desc->GetNaluLengthSize() == 1) {
            nalu_length = *data++;
            --size;
        } else if (avc_desc->GetNaluLengthSize() == 2) {
            nalu_length = AP4_BytesToUInt16BE(data);
            data += 2;
            size -= 2;
        } else if (avc_desc->GetNaluLengthSize() == 4) {
            nalu_length = AP4_BytesToUInt32BE(data);
            data += 4;
            size -= 4;
        } else {
            return false;
        }
        if (nalu_length <= size) {
            size -= nalu_length;
        } else {
            size = 0;
        }
        
        switch (*data & 0x1F) {
            case 1: {
                AP4_BitStream bits;
                bits.WriteBytes(data+1, 8);
                ReadGolomb(bits);
                unsigned int slice_type = ReadGolomb(bits);
                if (slice_type == 2 || slice_type == 7) {
                    return true;
                } else {
                    return false; // only show first slice type
                }
            }
            
            case 5: 
                return true;
        }
        
        data += nalu_length;
    }
 
    return false;
}
/*----------------------------------------------------------------------
|   AP4_CttsAtom::AP4_CttsAtom
+---------------------------------------------------------------------*/
AP4_CttsAtom::AP4_CttsAtom(AP4_UI32        size, 
                           AP4_UI08        version,
                           AP4_UI32        flags,
                           AP4_ByteStream& stream) :
    AP4_Atom(AP4_ATOM_TYPE_CTTS, size, version, flags)
{
    m_LookupCache.sample      = 0;
    m_LookupCache.entry_index = 0;

    AP4_UI32 entry_count;
    stream.ReadUI32(entry_count);
    m_Entries.SetItemCount(entry_count);
    unsigned char* buffer = new unsigned char[entry_count*8];
    AP4_Result result = stream.Read(buffer, entry_count*8);
    if (AP4_FAILED(result)) {
        delete[] buffer;
        return;
    }
    //bool use_quicktime_format = false;
    //AP4_SI32 quicktime_min_offset = 0;
    for (unsigned i=0; i<entry_count; i++) {
        m_Entries[i].m_SampleCount  = AP4_BytesToUInt32BE(&buffer[i*8  ]);
        AP4_UI32 offset             = AP4_BytesToUInt32BE(&buffer[i*8+4]);
        //if (offset & 0x80000000) {
        //    use_quicktime_format = true;
        //    AP4_SI32 noffset = (AP4_SI32)offset;
        //    if (noffset < quicktime_min_offset) quicktime_min_offset = noffset;
        //}
        m_Entries[i].m_SampleOffset = offset;
    }
    delete[] buffer;
    
    // in the quicktime format, the offsets can be positive or negative, so
    // we need to adjust for them here
    //if (use_quicktime_format) {
    //    for (unsigned i=0; i<entry_count; i++) {
    //        m_Entries[i].m_SampleOffset -= quicktime_min_offset;
    //    }
    //}
}
Beispiel #5
0
/*----------------------------------------------------------------------
|       AP4_ByteStream::ReadUI32
+---------------------------------------------------------------------*/
AP4_Result
AP4_ByteStream::ReadUI32(AP4_UI32& value)
{
    unsigned char buffer[4];

    // read bytes from the stream
    AP4_Result result;
    result = Read((void*)buffer, 4);
    if (AP4_FAILED(result)) {
        value = 0;
        return result;
    }

    // convert bytes to value
    value = AP4_BytesToUInt32BE(buffer);
    
    return AP4_SUCCESS;
}
Beispiel #6
0
/*----------------------------------------------------------------------
|   AP4_StcoAtom::AP4_StcoAtom
+---------------------------------------------------------------------*/
AP4_StcoAtom::AP4_StcoAtom(AP4_UI32        size, 
                           AP4_UI32        version,
                           AP4_UI32        flags,
                           AP4_ByteStream& stream) :
    AP4_Atom(AP4_ATOM_TYPE_STCO, size, version, flags)
{
    stream.ReadUI32(m_EntryCount);
    if (m_EntryCount > (size-AP4_FULL_ATOM_HEADER_SIZE-4)/4) {
        m_EntryCount = (size-AP4_FULL_ATOM_HEADER_SIZE-4)/4;
    }
    m_Entries = new AP4_UI32[m_EntryCount];
    unsigned char* buffer = new unsigned char[m_EntryCount*4];
    AP4_Result result = stream.Read(buffer, m_EntryCount*4);
    if (AP4_FAILED(result)) {
        delete[] buffer;
        return;
    }
    for (AP4_Ordinal i=0; i<m_EntryCount; i++) {
        m_Entries[i] = AP4_BytesToUInt32BE(&buffer[i*4]);
    }
    delete[] buffer;
}
Beispiel #7
0
/*----------------------------------------------------------------------
|   AP4_LinearReader::SeekTo
+---------------------------------------------------------------------*/
AP4_Result
AP4_LinearReader::SeekTo(AP4_UI32 time_ms, AP4_UI32* actual_time_ms)
{
    if (actual_time_ms) *actual_time_ms = time_ms; // default
    
    // we only support fragmented sources for now
    if (!m_HasFragments) return AP4_ERROR_NOT_SUPPORTED;
    
    // look for a fragment index
    if (m_Mfra == NULL) {
        if (m_FragmentStream) {
            // get the size of the stream (needed)
            AP4_LargeSize stream_size = 0;
            m_FragmentStream->GetSize(stream_size);

            if (stream_size > 12) {
                // remember where we are
                AP4_Position here;
                m_FragmentStream->Tell(here);
                
                // read the last 12 bytes
                unsigned char mfro[12];
                AP4_Result result = m_FragmentStream->Seek(stream_size-12);
                if (AP4_SUCCEEDED(result)) {
                    result = m_FragmentStream->Read(mfro, 12);
                }
                if (AP4_SUCCEEDED(result) && mfro[0] == 'm' && mfro[1] == 'f' && mfro[2] == 'r' && mfro[3] == 'o') {
                    AP4_UI32 mfra_size = AP4_BytesToUInt32BE(&mfro[8]);
                    if ((AP4_LargeSize)mfra_size < stream_size) {
                        result = m_FragmentStream->Seek(stream_size-mfra_size);
                        if (AP4_SUCCEEDED(result)) {
                            AP4_Atom* mfra = NULL;
                            AP4_LargeSize available = mfra_size;
                            AP4_DefaultAtomFactory::Instance.CreateAtomFromStream(*m_FragmentStream, available, mfra);
                            m_Mfra = AP4_DYNAMIC_CAST(AP4_ContainerAtom, mfra);
                        }
                    }
                }
                if (AP4_SUCCEEDED(result)) {
                    result = m_FragmentStream->Seek(here);
                }
            }
        }
    }
    
    // return now if we have not found an index
    if (m_Mfra == NULL) {
        return AP4_ERROR_NOT_SUPPORTED;
    }
    
    // look for the earliest fragment referenced by an entry with the largest timestamp that's
    // before or equal to the requested time
    int best_entry = -1;
    for (unsigned t=0; t<m_Trackers.ItemCount(); t++) {
        // find the tfra index for this track
        AP4_TfraAtom* tfra = NULL;
        for (AP4_List<AP4_Atom>::Item* item = m_Mfra->GetChildren().FirstItem();
                                       item;
                                       item = item->GetNext()) {
            if (item->GetData()->GetType() == AP4_ATOM_TYPE_TFRA) {
                AP4_TfraAtom* tfra_ = (AP4_TfraAtom*)item->GetData();
                if (tfra_->GetTrackId() == m_Trackers[t]->m_Track->GetId()) {
                    tfra = tfra_;
                    break;
                }
            }
        }
        if (tfra == NULL) {
            return AP4_ERROR_NOT_SUPPORTED;
        }
        AP4_Array<AP4_TfraAtom::Entry>& entries = tfra->GetEntries();

        AP4_UI64 media_time = AP4_ConvertTime(time_ms, 1000, m_Trackers[t]->m_Track->GetMediaTimeScale());
        int entry = -1;
        for (int i=0; i<(int)entries.ItemCount(); i++) {
            if (entries[i].m_Time > media_time) break;
            entry = i;
        }
        if (entry >= 0) {
            if (best_entry == -1) {
                best_entry = entry;
            } else if (entries[entry].m_MoofOffset < entries[best_entry].m_MoofOffset) {
                best_entry = entry;
            }

            // update our position
            if (best_entry >= 0) {
                if (actual_time_ms) {
                    // report the actual time we found (in milliseconds)
                    *actual_time_ms = (AP4_UI32)AP4_ConvertTime(entries[best_entry].m_Time, m_Trackers[t]->m_Track->GetMediaTimeScale(), 1000);
                }
                m_NextFragmentPosition = entries[best_entry].m_MoofOffset;
            }
        }
    }
    
    // check that we found something
    if (best_entry == -1) {
        return AP4_FAILURE;
    }
    
    // flush any queued samples
    FlushQueues();
    
    // reset tracker states
    for (unsigned int i=0; i<m_Trackers.ItemCount(); i++) {
        delete m_Trackers[i]->m_SampleTable;
        delete m_Trackers[i]->m_NextSample;
        m_Trackers[i]->m_SampleTable     = NULL;
        m_Trackers[i]->m_NextSample      = NULL;
        m_Trackers[i]->m_NextSampleIndex = 0;
        m_Trackers[i]->m_Eos             = false;
    }
        
    return AP4_SUCCESS;
}