Loading media/extractors/mp4/MPEG4Extractor.cpp +80 −53 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <ctype.h> #include <ctype.h> #include <inttypes.h> #include <inttypes.h> #include <algorithm> #include <memory> #include <memory> #include <stdint.h> #include <stdint.h> #include <stdlib.h> #include <stdlib.h> Loading Loading @@ -149,9 +150,13 @@ private: bool mIsAudio; bool mIsAudio; sp<ItemTable> mItemTable; sp<ItemTable> mItemTable; // Start offset from composition time to presentation time. /* Shift start offset (move to earlier time) when media_time > 0, // Support shift only for video tracks through mElstShiftStartTicks for now. * in media time scale. */ uint64_t mElstShiftStartTicks; uint64_t mElstShiftStartTicks; /* Initial start offset (move to later time), empty edit list entry * in media time scale. */ uint64_t mElstInitialEmptyEditTicks; uint64_t mElstInitialEmptyEditTicks; size_t parseNALSize(const uint8_t *data) const; size_t parseNALSize(const uint8_t *data) const; Loading Loading @@ -1215,7 +1220,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { off64_t entriesoffset = data_offset + 8; off64_t entriesoffset = data_offset + 8; uint64_t segment_duration; uint64_t segment_duration; int64_t media_time; int64_t media_time; uint64_t empty_edit_ticks = 0; bool empty_edit_present = false; bool empty_edit_present = false; for (int i = 0; i < entry_count; ++i) { for (int i = 0; i < entry_count; ++i) { switch (version) { switch (version) { Loading Loading @@ -1247,45 +1251,37 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { } } // Empty edit entry would have to be first entry. // Empty edit entry would have to be first entry. if (media_time == -1 && i == 0) { if (media_time == -1 && i == 0) { int64_t durationUs; if (AMediaFormat_getInt64(mFileMetaData, AMEDIAFORMAT_KEY_DURATION, &durationUs)) { empty_edit_ticks = segment_duration; ALOGV("initial empty edit ticks: %" PRIu64, empty_edit_ticks); empty_edit_present = true; empty_edit_present = true; } ALOGV("initial empty edit ticks: %" PRIu64, segment_duration); } /* In movie header timescale, and needs to be converted to media timescale * after we get that from a track's 'mdhd' atom, * which at times come after 'elst'. */ mLastTrack->elst_initial_empty_edit_ticks = segment_duration; } else if (media_time >= 0 && i == 0) { ALOGV("first edit list entry"); mLastTrack->elst_media_time = media_time; mLastTrack->elst_segment_duration = segment_duration; ALOGV("segment_duration: %" PRIu64 " media_time: %" PRId64, segment_duration, media_time); // media_time is in media timescale as are STTS/CTTS entries. mLastTrack->elst_shift_start_ticks = media_time; } else if (empty_edit_present && i == 1) { // Process second entry only when the first entry was an empty edit entry. // Process second entry only when the first entry was an empty edit entry. if (empty_edit_present && i == 1) { ALOGV("second edit list entry"); int64_t durationUs; mLastTrack->elst_media_time = media_time; if (AMediaFormat_getInt64(mLastTrack->meta, AMEDIAFORMAT_KEY_DURATION, mLastTrack->elst_segment_duration = segment_duration; &durationUs) && ALOGV("segment_duration: %" PRIu64 " media_time: %" PRId64, mHeaderTimescale != 0) { segment_duration, media_time); // Support only segment_duration<=track_duration and media_time==0 case. mLastTrack->elst_shift_start_ticks = media_time; uint64_t segmentDurationUs = } else { segment_duration * 1000000 / mHeaderTimescale; ALOGW("for now, unsupported entry in edit list %" PRIu32, entry_count); if (segmentDurationUs == 0 || segmentDurationUs > durationUs || media_time != 0) { ALOGW("for now, unsupported second entry in empty edit list"); } } } } } } // save these for later, because the elst atom might precede // save these for later, because the elst atom might precede // the atoms that actually gives us the duration and sample rate // the atoms that actually gives us the duration and sample rate // needed to calculate the padding and delay values // needed to calculate the padding and delay values mLastTrack->elst_needs_processing = true; mLastTrack->elst_needs_processing = true; if (empty_edit_present) { /* In movie header timescale, and needs to be converted to media timescale once * we get that from a track's 'mdhd' atom, which at times come after 'elst'. */ mLastTrack->elst_initial_empty_edit_ticks = empty_edit_ticks; } else { mLastTrack->elst_media_time = media_time; mLastTrack->elst_segment_duration = segment_duration; ALOGV("segment_duration: %" PRIu64 " media_time: %" PRId64, segment_duration, media_time); } } } break; break; } } Loading Loading @@ -4324,9 +4320,9 @@ MediaTrackHelper *MPEG4Extractor::getTrack(size_t index) { } } } } // media_time is in media timescale as are STTS/CTTS entries. track->elst_shift_start_ticks = track->elst_media_time; ALOGV("track->elst_shift_start_ticks :%" PRIu64, track->elst_shift_start_ticks); ALOGV("track->elst_shift_start_ticks :%" PRIu64, track->elst_shift_start_ticks); uint64_t elst_initial_empty_edit_ticks = 0; if (mHeaderTimescale != 0) { if (mHeaderTimescale != 0) { // Convert empty_edit_ticks from movie timescale to media timescale. // Convert empty_edit_ticks from movie timescale to media timescale. uint64_t elst_initial_empty_edit_ticks_mul = 0, elst_initial_empty_edit_ticks_add = 0; uint64_t elst_initial_empty_edit_ticks_mul = 0, elst_initial_empty_edit_ticks_add = 0; Loading @@ -4337,15 +4333,15 @@ MediaTrackHelper *MPEG4Extractor::getTrack(size_t index) { ALOGE("track->elst_initial_empty_edit_ticks overflow"); ALOGE("track->elst_initial_empty_edit_ticks overflow"); return nullptr; return nullptr; } } track->elst_initial_empty_edit_ticks = elst_initial_empty_edit_ticks_add / mHeaderTimescale; elst_initial_empty_edit_ticks = elst_initial_empty_edit_ticks_add / mHeaderTimescale; ALOGV("track->elst_initial_empty_edit_ticks :%" PRIu64, track->elst_initial_empty_edit_ticks); } } ALOGV("elst_initial_empty_edit_ticks in MediaTimeScale :%" PRIu64, elst_initial_empty_edit_ticks); MPEG4Source* source = MPEG4Source* source = new MPEG4Source(track->meta, mDataSource, track->timescale, track->sampleTable, new MPEG4Source(track->meta, mDataSource, track->timescale, track->sampleTable, mSidxEntries, trex, mMoofOffset, itemTable, mSidxEntries, trex, mMoofOffset, itemTable, track->elst_shift_start_ticks, track->elst_initial_empty_edit_ticks); track->elst_shift_start_ticks, elst_initial_empty_edit_ticks); if (source->init() != OK) { if (source->init() != OK) { delete source; delete source; return NULL; return NULL; Loading Loading @@ -5885,9 +5881,22 @@ media_status_t MPEG4Source::read( break; break; } } if( mode != ReadOptions::SEEK_FRAME_INDEX) { if( mode != ReadOptions::SEEK_FRAME_INDEX) { seekTimeUs += ((long double)mElstShiftStartTicks * 1000000) / mTimescale; int64_t elstInitialEmptyEditUs = 0, elstShiftStartUs = 0; ALOGV("shifted seekTimeUs :%" PRId64 ", mElstShiftStartTicks:%" PRIu64, seekTimeUs, if (mElstInitialEmptyEditTicks > 0) { mElstShiftStartTicks); elstInitialEmptyEditUs = ((long double)mElstInitialEmptyEditTicks * 1000000) / mTimescale; /* Sample's composition time from ctts/stts entries are non-negative(>=0). * Hence, lower bound on seekTimeUs is 0. */ seekTimeUs = std::max(seekTimeUs - elstInitialEmptyEditUs, (int64_t)0); } if (mElstShiftStartTicks > 0) { elstShiftStartUs = ((long double)mElstShiftStartTicks * 1000000) / mTimescale; seekTimeUs += elstShiftStartUs; } ALOGV("shifted seekTimeUs:%" PRId64 ", elstInitialEmptyEditUs:%" PRIu64 ", elstShiftStartUs:%" PRIu64, seekTimeUs, elstInitialEmptyEditUs, elstShiftStartUs); } } uint32_t sampleIndex; uint32_t sampleIndex; Loading Loading @@ -5933,7 +5942,12 @@ media_status_t MPEG4Source::read( if (mode == ReadOptions::SEEK_CLOSEST if (mode == ReadOptions::SEEK_CLOSEST || mode == ReadOptions::SEEK_FRAME_INDEX) { || mode == ReadOptions::SEEK_FRAME_INDEX) { if (mElstInitialEmptyEditTicks > 0) { sampleTime += mElstInitialEmptyEditTicks; } if (mElstShiftStartTicks > 0){ sampleTime -= mElstShiftStartTicks; sampleTime -= mElstShiftStartTicks; } targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale; targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale; } } Loading Loading @@ -5976,12 +5990,12 @@ media_status_t MPEG4Source::read( if(err == OK) { if(err == OK) { if (mElstInitialEmptyEditTicks > 0) { if (mElstInitialEmptyEditTicks > 0) { cts += mElstInitialEmptyEditTicks; cts += mElstInitialEmptyEditTicks; } else { } if (mElstShiftStartTicks > 0) { // cts can be negative. for example, initial audio samples for gapless playback. // cts can be negative. for example, initial audio samples for gapless playback. cts -= (int64_t)mElstShiftStartTicks; cts -= (int64_t)mElstShiftStartTicks; } } } } } else { } else { err = mItemTable->getImageOffsetAndSize( err = mItemTable->getImageOffsetAndSize( options && options->getSeekTo(&seekTimeUs, &mode) ? options && options->getSeekTo(&seekTimeUs, &mode) ? Loading Loading @@ -6261,10 +6275,22 @@ media_status_t MPEG4Source::fragmentedRead( int64_t seekTimeUs; int64_t seekTimeUs; ReadOptions::SeekMode mode; ReadOptions::SeekMode mode; if (options && options->getSeekTo(&seekTimeUs, &mode)) { if (options && options->getSeekTo(&seekTimeUs, &mode)) { int64_t elstInitialEmptyEditUs = 0, elstShiftStartUs = 0; seekTimeUs += ((long double)mElstShiftStartTicks * 1000000) / mTimescale; if (mElstInitialEmptyEditTicks > 0) { ALOGV("shifted seekTimeUs :%" PRId64 ", mElstShiftStartTicks:%" PRIu64, seekTimeUs, elstInitialEmptyEditUs = ((long double)mElstInitialEmptyEditTicks * 1000000) / mElstShiftStartTicks); mTimescale; /* Sample's composition time from ctts/stts entries are non-negative(>=0). * Hence, lower bound on seekTimeUs is 0. */ seekTimeUs = std::max(seekTimeUs - elstInitialEmptyEditUs, (int64_t)0); } if (mElstShiftStartTicks > 0){ elstShiftStartUs = ((long double)mElstShiftStartTicks * 1000000) / mTimescale; seekTimeUs += elstShiftStartUs; } ALOGV("shifted seekTimeUs:%" PRId64 ", elstInitialEmptyEditUs:%" PRIu64 ", elstShiftStartUs:%" PRIu64, seekTimeUs, elstInitialEmptyEditUs, elstShiftStartUs); int numSidxEntries = mSegments.size(); int numSidxEntries = mSegments.size(); if (numSidxEntries != 0) { if (numSidxEntries != 0) { Loading Loading @@ -6355,7 +6381,8 @@ media_status_t MPEG4Source::fragmentedRead( if (mElstInitialEmptyEditTicks > 0) { if (mElstInitialEmptyEditTicks > 0) { cts += mElstInitialEmptyEditTicks; cts += mElstInitialEmptyEditTicks; } else { } if (mElstShiftStartTicks > 0) { // cts can be negative. for example, initial audio samples for gapless playback. // cts can be negative. for example, initial audio samples for gapless playback. cts -= (int64_t)mElstShiftStartTicks; cts -= (int64_t)mElstShiftStartTicks; } } Loading media/extractors/mp4/MPEG4Extractor.h +2 −2 Original line number Original line Diff line number Diff line Loading @@ -88,9 +88,9 @@ private: */ */ int64_t elst_media_time; int64_t elst_media_time; uint64_t elst_segment_duration; uint64_t elst_segment_duration; // Shift start offset only when media_time > 0. // Shift start offset (move to earlier time) when media_time > 0. uint64_t elst_shift_start_ticks; uint64_t elst_shift_start_ticks; // Initial start offset, empty edit list entry. // Initial start offset (move to later time), from empty edit list entry. uint64_t elst_initial_empty_edit_ticks; uint64_t elst_initial_empty_edit_ticks; bool subsample_encryption; bool subsample_encryption; Loading Loading
media/extractors/mp4/MPEG4Extractor.cpp +80 −53 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <ctype.h> #include <ctype.h> #include <inttypes.h> #include <inttypes.h> #include <algorithm> #include <memory> #include <memory> #include <stdint.h> #include <stdint.h> #include <stdlib.h> #include <stdlib.h> Loading Loading @@ -149,9 +150,13 @@ private: bool mIsAudio; bool mIsAudio; sp<ItemTable> mItemTable; sp<ItemTable> mItemTable; // Start offset from composition time to presentation time. /* Shift start offset (move to earlier time) when media_time > 0, // Support shift only for video tracks through mElstShiftStartTicks for now. * in media time scale. */ uint64_t mElstShiftStartTicks; uint64_t mElstShiftStartTicks; /* Initial start offset (move to later time), empty edit list entry * in media time scale. */ uint64_t mElstInitialEmptyEditTicks; uint64_t mElstInitialEmptyEditTicks; size_t parseNALSize(const uint8_t *data) const; size_t parseNALSize(const uint8_t *data) const; Loading Loading @@ -1215,7 +1220,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { off64_t entriesoffset = data_offset + 8; off64_t entriesoffset = data_offset + 8; uint64_t segment_duration; uint64_t segment_duration; int64_t media_time; int64_t media_time; uint64_t empty_edit_ticks = 0; bool empty_edit_present = false; bool empty_edit_present = false; for (int i = 0; i < entry_count; ++i) { for (int i = 0; i < entry_count; ++i) { switch (version) { switch (version) { Loading Loading @@ -1247,45 +1251,37 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { } } // Empty edit entry would have to be first entry. // Empty edit entry would have to be first entry. if (media_time == -1 && i == 0) { if (media_time == -1 && i == 0) { int64_t durationUs; if (AMediaFormat_getInt64(mFileMetaData, AMEDIAFORMAT_KEY_DURATION, &durationUs)) { empty_edit_ticks = segment_duration; ALOGV("initial empty edit ticks: %" PRIu64, empty_edit_ticks); empty_edit_present = true; empty_edit_present = true; } ALOGV("initial empty edit ticks: %" PRIu64, segment_duration); } /* In movie header timescale, and needs to be converted to media timescale * after we get that from a track's 'mdhd' atom, * which at times come after 'elst'. */ mLastTrack->elst_initial_empty_edit_ticks = segment_duration; } else if (media_time >= 0 && i == 0) { ALOGV("first edit list entry"); mLastTrack->elst_media_time = media_time; mLastTrack->elst_segment_duration = segment_duration; ALOGV("segment_duration: %" PRIu64 " media_time: %" PRId64, segment_duration, media_time); // media_time is in media timescale as are STTS/CTTS entries. mLastTrack->elst_shift_start_ticks = media_time; } else if (empty_edit_present && i == 1) { // Process second entry only when the first entry was an empty edit entry. // Process second entry only when the first entry was an empty edit entry. if (empty_edit_present && i == 1) { ALOGV("second edit list entry"); int64_t durationUs; mLastTrack->elst_media_time = media_time; if (AMediaFormat_getInt64(mLastTrack->meta, AMEDIAFORMAT_KEY_DURATION, mLastTrack->elst_segment_duration = segment_duration; &durationUs) && ALOGV("segment_duration: %" PRIu64 " media_time: %" PRId64, mHeaderTimescale != 0) { segment_duration, media_time); // Support only segment_duration<=track_duration and media_time==0 case. mLastTrack->elst_shift_start_ticks = media_time; uint64_t segmentDurationUs = } else { segment_duration * 1000000 / mHeaderTimescale; ALOGW("for now, unsupported entry in edit list %" PRIu32, entry_count); if (segmentDurationUs == 0 || segmentDurationUs > durationUs || media_time != 0) { ALOGW("for now, unsupported second entry in empty edit list"); } } } } } } // save these for later, because the elst atom might precede // save these for later, because the elst atom might precede // the atoms that actually gives us the duration and sample rate // the atoms that actually gives us the duration and sample rate // needed to calculate the padding and delay values // needed to calculate the padding and delay values mLastTrack->elst_needs_processing = true; mLastTrack->elst_needs_processing = true; if (empty_edit_present) { /* In movie header timescale, and needs to be converted to media timescale once * we get that from a track's 'mdhd' atom, which at times come after 'elst'. */ mLastTrack->elst_initial_empty_edit_ticks = empty_edit_ticks; } else { mLastTrack->elst_media_time = media_time; mLastTrack->elst_segment_duration = segment_duration; ALOGV("segment_duration: %" PRIu64 " media_time: %" PRId64, segment_duration, media_time); } } } break; break; } } Loading Loading @@ -4324,9 +4320,9 @@ MediaTrackHelper *MPEG4Extractor::getTrack(size_t index) { } } } } // media_time is in media timescale as are STTS/CTTS entries. track->elst_shift_start_ticks = track->elst_media_time; ALOGV("track->elst_shift_start_ticks :%" PRIu64, track->elst_shift_start_ticks); ALOGV("track->elst_shift_start_ticks :%" PRIu64, track->elst_shift_start_ticks); uint64_t elst_initial_empty_edit_ticks = 0; if (mHeaderTimescale != 0) { if (mHeaderTimescale != 0) { // Convert empty_edit_ticks from movie timescale to media timescale. // Convert empty_edit_ticks from movie timescale to media timescale. uint64_t elst_initial_empty_edit_ticks_mul = 0, elst_initial_empty_edit_ticks_add = 0; uint64_t elst_initial_empty_edit_ticks_mul = 0, elst_initial_empty_edit_ticks_add = 0; Loading @@ -4337,15 +4333,15 @@ MediaTrackHelper *MPEG4Extractor::getTrack(size_t index) { ALOGE("track->elst_initial_empty_edit_ticks overflow"); ALOGE("track->elst_initial_empty_edit_ticks overflow"); return nullptr; return nullptr; } } track->elst_initial_empty_edit_ticks = elst_initial_empty_edit_ticks_add / mHeaderTimescale; elst_initial_empty_edit_ticks = elst_initial_empty_edit_ticks_add / mHeaderTimescale; ALOGV("track->elst_initial_empty_edit_ticks :%" PRIu64, track->elst_initial_empty_edit_ticks); } } ALOGV("elst_initial_empty_edit_ticks in MediaTimeScale :%" PRIu64, elst_initial_empty_edit_ticks); MPEG4Source* source = MPEG4Source* source = new MPEG4Source(track->meta, mDataSource, track->timescale, track->sampleTable, new MPEG4Source(track->meta, mDataSource, track->timescale, track->sampleTable, mSidxEntries, trex, mMoofOffset, itemTable, mSidxEntries, trex, mMoofOffset, itemTable, track->elst_shift_start_ticks, track->elst_initial_empty_edit_ticks); track->elst_shift_start_ticks, elst_initial_empty_edit_ticks); if (source->init() != OK) { if (source->init() != OK) { delete source; delete source; return NULL; return NULL; Loading Loading @@ -5885,9 +5881,22 @@ media_status_t MPEG4Source::read( break; break; } } if( mode != ReadOptions::SEEK_FRAME_INDEX) { if( mode != ReadOptions::SEEK_FRAME_INDEX) { seekTimeUs += ((long double)mElstShiftStartTicks * 1000000) / mTimescale; int64_t elstInitialEmptyEditUs = 0, elstShiftStartUs = 0; ALOGV("shifted seekTimeUs :%" PRId64 ", mElstShiftStartTicks:%" PRIu64, seekTimeUs, if (mElstInitialEmptyEditTicks > 0) { mElstShiftStartTicks); elstInitialEmptyEditUs = ((long double)mElstInitialEmptyEditTicks * 1000000) / mTimescale; /* Sample's composition time from ctts/stts entries are non-negative(>=0). * Hence, lower bound on seekTimeUs is 0. */ seekTimeUs = std::max(seekTimeUs - elstInitialEmptyEditUs, (int64_t)0); } if (mElstShiftStartTicks > 0) { elstShiftStartUs = ((long double)mElstShiftStartTicks * 1000000) / mTimescale; seekTimeUs += elstShiftStartUs; } ALOGV("shifted seekTimeUs:%" PRId64 ", elstInitialEmptyEditUs:%" PRIu64 ", elstShiftStartUs:%" PRIu64, seekTimeUs, elstInitialEmptyEditUs, elstShiftStartUs); } } uint32_t sampleIndex; uint32_t sampleIndex; Loading Loading @@ -5933,7 +5942,12 @@ media_status_t MPEG4Source::read( if (mode == ReadOptions::SEEK_CLOSEST if (mode == ReadOptions::SEEK_CLOSEST || mode == ReadOptions::SEEK_FRAME_INDEX) { || mode == ReadOptions::SEEK_FRAME_INDEX) { if (mElstInitialEmptyEditTicks > 0) { sampleTime += mElstInitialEmptyEditTicks; } if (mElstShiftStartTicks > 0){ sampleTime -= mElstShiftStartTicks; sampleTime -= mElstShiftStartTicks; } targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale; targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale; } } Loading Loading @@ -5976,12 +5990,12 @@ media_status_t MPEG4Source::read( if(err == OK) { if(err == OK) { if (mElstInitialEmptyEditTicks > 0) { if (mElstInitialEmptyEditTicks > 0) { cts += mElstInitialEmptyEditTicks; cts += mElstInitialEmptyEditTicks; } else { } if (mElstShiftStartTicks > 0) { // cts can be negative. for example, initial audio samples for gapless playback. // cts can be negative. for example, initial audio samples for gapless playback. cts -= (int64_t)mElstShiftStartTicks; cts -= (int64_t)mElstShiftStartTicks; } } } } } else { } else { err = mItemTable->getImageOffsetAndSize( err = mItemTable->getImageOffsetAndSize( options && options->getSeekTo(&seekTimeUs, &mode) ? options && options->getSeekTo(&seekTimeUs, &mode) ? Loading Loading @@ -6261,10 +6275,22 @@ media_status_t MPEG4Source::fragmentedRead( int64_t seekTimeUs; int64_t seekTimeUs; ReadOptions::SeekMode mode; ReadOptions::SeekMode mode; if (options && options->getSeekTo(&seekTimeUs, &mode)) { if (options && options->getSeekTo(&seekTimeUs, &mode)) { int64_t elstInitialEmptyEditUs = 0, elstShiftStartUs = 0; seekTimeUs += ((long double)mElstShiftStartTicks * 1000000) / mTimescale; if (mElstInitialEmptyEditTicks > 0) { ALOGV("shifted seekTimeUs :%" PRId64 ", mElstShiftStartTicks:%" PRIu64, seekTimeUs, elstInitialEmptyEditUs = ((long double)mElstInitialEmptyEditTicks * 1000000) / mElstShiftStartTicks); mTimescale; /* Sample's composition time from ctts/stts entries are non-negative(>=0). * Hence, lower bound on seekTimeUs is 0. */ seekTimeUs = std::max(seekTimeUs - elstInitialEmptyEditUs, (int64_t)0); } if (mElstShiftStartTicks > 0){ elstShiftStartUs = ((long double)mElstShiftStartTicks * 1000000) / mTimescale; seekTimeUs += elstShiftStartUs; } ALOGV("shifted seekTimeUs:%" PRId64 ", elstInitialEmptyEditUs:%" PRIu64 ", elstShiftStartUs:%" PRIu64, seekTimeUs, elstInitialEmptyEditUs, elstShiftStartUs); int numSidxEntries = mSegments.size(); int numSidxEntries = mSegments.size(); if (numSidxEntries != 0) { if (numSidxEntries != 0) { Loading Loading @@ -6355,7 +6381,8 @@ media_status_t MPEG4Source::fragmentedRead( if (mElstInitialEmptyEditTicks > 0) { if (mElstInitialEmptyEditTicks > 0) { cts += mElstInitialEmptyEditTicks; cts += mElstInitialEmptyEditTicks; } else { } if (mElstShiftStartTicks > 0) { // cts can be negative. for example, initial audio samples for gapless playback. // cts can be negative. for example, initial audio samples for gapless playback. cts -= (int64_t)mElstShiftStartTicks; cts -= (int64_t)mElstShiftStartTicks; } } Loading
media/extractors/mp4/MPEG4Extractor.h +2 −2 Original line number Original line Diff line number Diff line Loading @@ -88,9 +88,9 @@ private: */ */ int64_t elst_media_time; int64_t elst_media_time; uint64_t elst_segment_duration; uint64_t elst_segment_duration; // Shift start offset only when media_time > 0. // Shift start offset (move to earlier time) when media_time > 0. uint64_t elst_shift_start_ticks; uint64_t elst_shift_start_ticks; // Initial start offset, empty edit list entry. // Initial start offset (move to later time), from empty edit list entry. uint64_t elst_initial_empty_edit_ticks; uint64_t elst_initial_empty_edit_ticks; bool subsample_encryption; bool subsample_encryption; Loading