📄 mp4.cpp
字号:
return MP4_ERROR_NO_ERROR;}MP4_ERROR MP4Demux::Next (RMint64 currentTime){ if (!m_chpl_present) return MP4_ERROR_NOT_ALLOWED; DEBUGMSG (1, ("MP4Demux::Next, currentTime = %d\n", (RMint32)currentTime)); // find the current chapter we are on RMint32 i, currentChapter = 0, nextChapter; for (i=0; i<(RMint32)m_nchapters; i++) { DEBUGMSG (1, ("MP4Demux::Next, chapter = %d, time = %d\n", i, (RMint32)m_mp4Chapters[i].time)); if (m_mp4Chapters[i].time > currentTime) { if (i) { currentChapter = i - 1; break; } else currentChapter = 0; } } if (i == (RMint32)m_nchapters) { DEBUGMSG (1, ("MP4Demux::Next, last chapter\n")); nextChapter = 0; } else { DEBUGMSG (1, ("MP4Demux::Next, current chapter = %d\n", (RMint32)currentChapter)); nextChapter = currentChapter + 1; } DEBUGMSG (1, ("MP4Demux::Next, seeking to %d, %s\n", (RMint32)m_mp4Chapters[nextChapter].time, m_mp4Chapters[nextChapter].name)); return Seek (m_mp4Chapters[nextChapter].time);}MP4_ERROR MP4Demux::Previous (RMint64 currentTime){ if (!m_chpl_present) return MP4_ERROR_NOT_ALLOWED; DEBUGMSG (1, ("MP4Demux::Previous, currentTime = %d\n", (RMint32)currentTime)); // find the current chapter we are on RMint32 i, currentChapter = 0, prevChapter; for (i=0; i<(RMint32)m_nchapters; i++) { DEBUGMSG (1, ("MP4Demux::Previous, chapter = %d, time = %d\n", i, (RMint32)m_mp4Chapters[i].time)); if (m_mp4Chapters[i].time > currentTime) { if (i) { currentChapter = i - 1; break; } else currentChapter = 0; } } if (i == 0) { DEBUGMSG (1, ("MP4Demux::Previous, first chapter\n")); return MP4_ERROR_NOT_ALLOWED; } else { DEBUGMSG (1, ("MP4Demux::Previous, current chapter = %d\n", (RMint32)currentChapter)); if (currentChapter == 0) { prevChapter = 0; } else { prevChapter = currentChapter - 1; } } DEBUGMSG (1, ("MP4Demux::Previous, seeking to %d, %s\n", (RMint32)m_mp4Chapters[prevChapter].time, m_mp4Chapters[prevChapter].name)); return Seek (m_mp4Chapters[prevChapter].time);}MP4_ERROR MP4Demux::RandomAccessPointsOnly (RMint64 currentTime, RMint32 direction){ if (m_video_stss.IsInitialized () == 0) return MP4_ERROR_NOT_IMPLEMENTED; if (direction == 0) { if (m_RandomAccessPointsOnly) { m_next_next_chunk = 0; m_RandomAccessPointsOnly = 0; m_State = MP4_DEMUX_STATE_GET_DATA; return MP4_ERROR_NO_ERROR; } return MP4_ERROR_NOT_ALLOWED; } if (m_RandomAccessPointsOnly) { DEBUGMSG (1, ("RandomAccessPointsOnly: already in random access points only mode\n")); if (m_videoDSILength) m_CallbackTable.putDSI (0, 0, m_videoDSI, m_videoDSILength, (RMint64)m_tracktimescales[m_videoTrackIndex]/2, m_CallbackTable.context); return MP4_ERROR_NO_ERROR; } m_CallbackTable.info (MP4_MSG_FLUSH_START, 0, m_CallbackTable.context); while (m_State != MP4_DEMUX_STATE_GET_DATA) { if (Schedule () == MP4_ERROR_END_OF_FILE) return MP4_ERROR_NOT_ALLOWED; } m_CallbackTable.info (MP4_MSG_FLUSH_END, 0, m_CallbackTable.context); // a very cheap and easy way to convert time to sample ... // it may not work in all cases though ... RMuint32 samplecnt; currentTime = currentTime * m_tracktimescales[m_videoTrackIndex] / 1000; samplecnt = (RMuint32)(currentTime / m_video_stts_sample_delta); DEBUGMSG (1, ("start random access at sample %lu\n", samplecnt)); // do a binary search looking for sample closest to samplecnt RMuint32 istart, imiddle, iend, error; RMuint32 random_access_point_sample_no; istart = 0; iend = m_video_stss.entrycount (); imiddle = (istart + iend) / 2; random_access_point_sample_no = 0; while (1) { m_video_stss.seek (imiddle * 4); random_access_point_sample_no = m_video_stss.get32 (&error) - 1; m_video_stss.advance32 (&error); if ((imiddle == istart) || (imiddle == iend) || (random_access_point_sample_no == samplecnt)) { if (random_access_point_sample_no != samplecnt) { if (direction > 0) imiddle = iend; else imiddle = istart; m_video_stss.seek (imiddle * 4); random_access_point_sample_no = m_video_stss.get32 (&error) - 1; m_video_stss.advance32 (&error); } break; } if (samplecnt > random_access_point_sample_no) istart = imiddle; else iend = imiddle; imiddle = (istart + iend) / 2; } ASSERT (random_access_point_sample_no >= 0); m_currentRandomAccessPoint = random_access_point_sample_no; m_RandomAccessPointsOnly = direction; if (direction < 0) { m_video_stss.rewind32 (&error); ASSERT (error == 0); } RMuint32 frame_no; RMuint32 i; RMuint32 first_chunk, samples_per_chunk, sample_description_index; RMuint32 prev_samples_per_chunk, prev_first_chunk, frame_incr; frame_no = 0; m_video_sample_count = frame_no; m_video_stsc.reset (); prev_first_chunk = m_video_stsc.get32 (&error); m_video_chunk_index = prev_first_chunk; m_video_stsc.advance32 (&error); ASSERT (error == 0); prev_samples_per_chunk = m_video_stsc.get32 (&error); m_video_samples_per_chunk = prev_samples_per_chunk; m_samples_per_chunk = m_video_samples_per_chunk; m_video_stsc.advance32 (&error); ASSERT (error == 0); sample_description_index = m_video_stsc.get32 (&error); m_video_stsc.advance32 (&error); ASSERT (error == 0); for (i=0; i<m_video_stsc.entrycount (); i++) { first_chunk = m_video_stsc.get32 (&error); frame_incr = prev_samples_per_chunk * (first_chunk - prev_first_chunk); if ((frame_no + frame_incr) >= m_currentRandomAccessPoint) break; frame_no += frame_incr; m_video_stsc.advance32 (&error); ASSERT (error == 0); samples_per_chunk = m_video_stsc.get32 (&error); m_video_stsc.advance32 (&error); ASSERT (error == 0); sample_description_index = m_video_stsc.get32 (&error); m_video_stsc.advance32 (&error); ASSERT (error == 0); prev_first_chunk = first_chunk; prev_samples_per_chunk = samples_per_chunk; } m_video_sample_count = frame_no; m_video_chunk_index = prev_first_chunk; m_video_samples_per_chunk = prev_samples_per_chunk; m_samples_per_chunk = prev_samples_per_chunk; if (m_videoDSILength) m_CallbackTable.putDSI (0, 0, m_videoDSI, m_videoDSILength, (RMint64)m_tracktimescales[m_videoTrackIndex]/2, m_CallbackTable.context); m_next_next_chunk = 0; m_pRandomAccessData = 0; m_State = MP4_RANDOM_ACCESS_ONLY; m_RandomAccessState = PROCESS_CURRENT_RANDOM_ACCESS_POINT; return MP4_ERROR_NO_ERROR;}RMint32 MP4Demux::GetNumberOfAudioStreams (){ return m_naudioStreams;}RMint32 MP4Demux::GetNumberOfSubpictureStreams (){ return m_nspStreams;}MP4_ERROR MP4Demux::videoSeek (RMuint64 position_in_ms, RMuint32 *fileoffset){ m_video_stco.reset (); m_video_stts.reset (); m_video_ctts.reset (); m_video_stsz.reset (); m_video_stsc.reset (); m_video_stss.reset (); m_video_chunk_index = 1; m_video_samples_per_chunk = 1; m_video_sample_count = 0; m_video_stts_sample_delta_count = 0; m_video_ctts_sample_delta_count = 0; m_video_ctts_sample_delta = 0; m_videoTime = 0; m_samples_per_chunk = 0; m_chunkFlags = 0; m_total_chunk_size = 0; RMuint32 frame_no, chunk_offset; RMuint32 error; RMuint32 i, j; RMuint32 first_chunk, samples_per_chunk, sample_description_index; RMuint32 prev_samples_per_chunk, prev_first_chunk, frame_incr; RMuint32 sample_delta, sync_sample; RMuint64 time; // seek to the correct stsc and stts table position time = position_in_ms * m_tracktimescales[m_videoTrackIndex] / 1000; m_video_stts_sample_delta_count = 0; frame_no = 0; prev_first_chunk = 1; sample_delta = 0; sync_sample = 0; ASSERT (m_video_stsc.IsInitialized ()); for (i=0; i<m_video_stsc.entrycount (); i++) { first_chunk = m_video_stsc.get32 (&error); m_video_stsc.advance32 (&error); ASSERT (error == 0); samples_per_chunk = m_video_stsc.get32 (&error); m_video_stsc.advance32 (&error); ASSERT (error == 0); sample_description_index = m_video_stsc.get32 (&error); m_video_stsc.advance32 (&error); ASSERT (error == 0); frame_incr = prev_samples_per_chunk * (first_chunk - prev_first_chunk); frame_no += frame_incr; // calculate the time of this frame to compare it to the requested time if (m_video_stts.entrycount () == 0) { if (m_video_stts_sample_delta_count == 0) { m_video_stts_sample_delta_count = m_video_stts.get32 (&error); m_video_stts.advance32 (&error); ASSERT (error == 0); sample_delta = m_video_stts.get32 (&error); m_video_stts.advance32 (&error); ASSERT (error == 0); ASSERT (sample_delta); } ASSERT (sample_delta); m_videoTime += (frame_incr * sample_delta); } else { for (j=0; j<frame_incr; j++) { if (m_video_stts_sample_delta_count == 0) { m_video_stts_sample_delta_count = m_video_stts.get32 (&error); m_video_stts.advance32 (&error); ASSERT (error == 0); sample_delta = m_video_stts.get32 (&error); m_video_stts.advance32 (&error); ASSERT (error == 0); ASSERT (sample_delta); } m_videoTime += sample_delta; m_video_stts_sample_delta_count--; } } if (m_videoTime >= time) { m_video_stsc.seek (i * 12); m_video_samples_per_chunk = samples_per_chunk; m_video_chunk_index = first_chunk; m_video_sample_count = frame_no; break; } prev_first_chunk = first_chunk; prev_samples_per_chunk = samples_per_chunk; } ASSERT (i < m_video_stsc.entrycount ()); // seek to the correct ctts table position if (m_video_ctts.IsInitialized ()) { RMuint32 i, j, framecnt, n; framecnt = 0; error = 0; for (i=0; i<m_video_ctts.entrycount (); i++) { n = m_video_ctts_sample_delta_count = m_video_ctts.get32 (&error); m_video_ctts.advance32 (&error); ASSERT (error == 0); m_video_ctts_sample_delta = m_video_ctts.get32 (&error); m_video_ctts.advance32 (&error); ASSERT (error == 0); for (j=0; j<n; j++) { m_video_ctts_sample_delta_count--; framecnt++; if (framecnt == frame_no) { goto video_ctts_table_finished; } } } ASSERT (0); }video_ctts_table_finished: // seek to the correct stsz table position ASSERT (m_video_stsz.IsInitialized ()); if (m_video_sample_size == 0) m_video_stsz.seek (frame_no * 4); // seek to the correct stco table offset ASSERT (m_video_stco.IsInitialized ()); ASSERT (m_video_chunk_index); m_video_stco.seek ((m_video_chunk_index - 1) * 4); chunk_offset = m_video_stco.get32 (&error); DEBUGMSG (1, ("-------------------------\n")); DEBUGMSG (1, ("VIDEO SEEK (fast method):\n")); DEBUGMSG (1, ("m_video_chunk_index: %lu\n", m_video_chunk_index)); DEBUGMSG (1, ("m_video_samples_per_chunk: %lu\n", m_video_samples_per_chunk)); DEBUGMSG (1, ("m_video_sample_count: %lu\n", m_video_sample_count)); DEBUGMSG (1, ("m_video_stts_sample_delta_count: %lu\n", m_video_stts_sample_delta_count)); DEBUGMSG (1, ("m_video_ctts_sample_delta_count: %lu\n", m_video_ctts_sample_delta_count)); DEBUGMSG (1, ("m_video_ctts_sample_delta: %lu\n", m_video_ctts_sample_delta)); DEBUGMSG (1, ("m_videoTime: %lu\n", m_videoTime)); DEBUGMSG (1, ("stco: %lu, %lu\n", m_video_stco.tell (), m_video_stco.get32 (&error))); DEBUGMSG (1, ("stts: %lu, %lu\n", m_video_stts.tell (), m_video_stts.get32 (&error))); DEBUGMSG (1, ("ctts: %lu, %lu\n", m_video_ctts.tell (), m_video_ctts.get32 (&error))); DEBUGMSG (1, ("stsz: %lu, %lu\n", m_video_stsz.tell (), m_video_stsz.get32 (&error))); DEBUGMSG (1, ("stsc: %lu, %lu\n", m_video_stsc.tell (), m_video_stsc.get32 (&error))); DEBUGMSG (1, ("-------------------------\n")); *fileoffset = chunk_offset; return MP4_ERROR_NO_ERROR; // the code below is a brute force methos to do seek, // it is really slow, but good for debugging if you want to check the results of // the above code m_video_stco.reset (); m_video_stts.reset (); m_video_ctts.reset (); m_video_stsz.reset (); m_video_stsc.reset (); m_video_chunk_index = 1; m_video_samples_per_chunk = 1; m_video_sample_count = 0; m_video_stts_sample_delta_count = 0; m_video_ctts_sample_delta_count = 0; m_video_ctts_sample_delta = 0; m_videoTime = 0; m_samples_per_chunk = 0; m_chunkFlags = 0; m_total_chunk_size = 0; RMuint32 chunk_length, first_entry; RMuint32 percent0, percent1; percent0 = (RMuint32)-1; while (1) { chunk_offset = m_video_stco.get32 (&error); if (error)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -