📄 mp4.cpp
字号:
#include <stdio.h>#include <memory.h>#include <string.h>#include "mp4.h"int gettime ();#if 0#define MP4_ENABLE_DEBUG 1static FILE *f = 0;#ifdef _WIN32#include <windows.h>static void debug_outs (char *szMsg, ...){ char szBuf[256]; wvsprintf (szBuf, szMsg, (LPSTR)(&szMsg + 1)); OutputDebugString (szBuf);}static void debug_break (void) { _asm int 3;}#else#include <stdio.h>#define debug_outs printfstatic void debug_break (void) {}#endif#define ASSERT(exp) ((void)((exp)?1:(debug_outs ("ASSERT failed: line %d, file %s\n", __LINE__,__FILE__), debug_break(), 0)))#define DEBUGMSG(cond,printf_exp) ((void)((cond)?(debug_outs printf_exp),1:0))#else#define ASSERT(exp)#define DEBUGMSG(cond,printf_exp)#endif#define MP4_SWAP_ENDIANESS32(x) (((x & 0x000000ff) << 24) | ((x & 0x0000ff00) << 8) | ((x & 0x00ff0000) >> 8) | ((x & 0xff000000) >> 24))#define MP4_SWAP_ENDIANESS16(x) (((x & 0x00ff) << 8) | ((x & 0xff00) >> 8))#define MP4_DEMUX_STATE_GET_DATA 0#define MP4_DEMUX_STATE_READ_DATA 1#define MP4_DEMUX_STATE_PARSE_DATA 2#define MP4_DEMUX_STATE_PARSE_CHUNK 3#define MP4_DEMUX_STATE_SEND_DATA 4#define MP4_RANDOM_ACCESS_ONLY 5#define MP4_DEMUX_STATE_END_OF_FILE 6#define MP4_MIN(X,Y) (((X)<=(Y))?(X):(Y)) // to find the min between two number.#define MP4_MAX(X,Y) (((X)>=(Y))?(X):(Y)) // to find the min between two number.MP4Demux::MP4Demux (){}MP4Demux::~MP4Demux (){ if (m_handle) m_CallbackTable.fclose (m_handle, m_CallbackTable.context);}MP4_ERROR MP4Demux::Init (){ RMint32 i; m_valid = 0; m_tmpidx = MP4_MIN_READ_LENGTH; m_handle = 0; m_videoDSILength = 0; for (i=0; i<MP4_MAX_AUDIOTRACKS; i++) m_audioDSILength[i] = 0; for (i=0; i<MP4_MAX_SUBPICTRACKS; i++) m_spDSILength[i] = 0; m_currentHandlerType = 0; m_mdatpos = 0; m_pData = 0; m_total_chunk_size = 0; m_samples_per_chunk = 0; m_chunkTime = 0; m_video_samples_per_chunk = 0; m_video_sample_count = 0; m_videoTime = 0; m_video_stts_sample_delta_count = 0; m_video_ctts_sample_delta_count = 0; m_video_ctts_sample_delta = 0; for (i=0; i<MP4_MAX_AUDIOTRACKS; i++) { m_audio_samples_per_chunk[i] = 0; m_audio_sample_count[i] = 0; m_audioTime[i] = 0; m_audio_stts_sample_delta_count[i] = 0; m_audio_ctts_sample_delta_count[i] = 0; m_audio_ctts_sample_delta[i] = 0; } for (i=0; i<MP4_MAX_SUBPICTRACKS; i++) { m_subpi_samples_per_chunk[i] = 0; m_subpi_sample_count[i] = 0; m_subpiTime[i] = 0; m_subpi_stts_sample_delta_count[i] = 0; m_subpi_ctts_sample_delta_count[i] = 0; m_subpi_ctts_sample_delta[i] = 0; } m_trackindex = -1; for (i=0; i<MP4_MAX_TRACKS; i++) { m_trackids[i] = 0; m_tracktimescales[i] = 0; m_spWidth[i] = 720; m_spHeight[i] = 480; } m_videoTrackIndex = -1; for (i=0; i<MP4_MAX_AUDIOTRACKS; i++) m_audioTrackIndex[i] = -1; for (i=0; i<MP4_MAX_SUBPICTRACKS; i++) m_subpiTrackIndex[i] = -1; m_visualHeight = 480; m_visualWidth = 720; m_firstVideoChunk = 1; m_chpl_present = 0; m_naudioStreams = 0; m_nspStreams = 0; m_RandomAccessPointsOnly = 0; m_next_next_chunk = 0; m_currentAudioTrack = 0; m_currentSubpiTrack = 0; m_skipcount = 0; m_skipcount_resetvalue = 0; return MP4_ERROR_NO_ERROR;}MP4_ERROR MP4Demux::InitCallbackTable (MP4_CALLBACK_TABLE *pTable){ m_CallbackTable.context = pTable->context; m_CallbackTable.fopen = pTable->fopen; m_CallbackTable.fseek = pTable->fseek; m_CallbackTable.ftell = pTable->ftell; m_CallbackTable.fread = pTable->fread; m_CallbackTable.fclose = pTable->fclose; m_CallbackTable.addref = pTable->addref; m_CallbackTable.release = pTable->release; m_CallbackTable.info = pTable->info; m_CallbackTable.getData = pTable->getData; m_CallbackTable.putDSI = pTable->putDSI; m_CallbackTable.putChunk = pTable->putChunk; return MP4_ERROR_NO_ERROR;}MP4_ERROR MP4Demux::Demux (RMint8 *filename){ RMint32 i; ASSERT (m_handle == 0); DEBUGMSG (1, ("MP4Demux::Demux (%s)\n", filename)); m_handle = m_CallbackTable.fopen (filename, m_CallbackTable.context); ASSERT (m_handle); if (m_handle == 0) return MP4_ERROR_FILE_NOT_FOUND; while (NextBox (0) == 0); ASSERT (m_video_stco.IsInitialized ()); ASSERT (m_video_stsz.IsInitialized ()); ASSERT (m_video_stsc.IsInitialized ()); ASSERT (m_audio_stco[0].IsInitialized ()); ASSERT (m_audio_stsz[0].IsInitialized ()); ASSERT (m_audio_stsc[0].IsInitialized ()); RMuint32 video_present, audio_present; video_present = m_video_stco.IsInitialized () && m_video_stsz.IsInitialized () && m_video_stsc.IsInitialized (); audio_present = m_audio_stco[0].IsInitialized () && m_audio_stsz[0].IsInitialized () && m_audio_stsc[0].IsInitialized (); if ((video_present == 0) && (audio_present == 0)) { return MP4_ERROR_FILE_NOT_SUPPORTED; } m_currentOffset = m_mdatpos; ASSERT (m_currentOffset); m_State = MP4_DEMUX_STATE_GET_DATA; m_CallbackTable.fseek (m_handle, m_mdatpos, SEEK_SET, m_CallbackTable.context); m_video_chunk_index = 1; TRACK_TIMESCALE ts; for (i=0; i<MP4_MAX_AUDIOTRACKS; i++) { m_audio_chunk_index[i] = 1; if (m_audioTrackIndex[i] != -1) ts.audioTimeScale[i] = m_tracktimescales[m_audioTrackIndex[i]]; else ts.audioTimeScale[i] = 0; } for (i=0; i<MP4_MAX_SUBPICTRACKS; i++) { m_subpi_chunk_index[i] = 1; if (m_subpiTrackIndex[i] != -1) ts.subpiTimeScale[i] = m_tracktimescales[m_subpiTrackIndex[i]]; else ts.subpiTimeScale[i] = 0; } if (m_videoTrackIndex != -1) ts.videoTimeScale = m_tracktimescales[m_videoTrackIndex]; else ts.videoTimeScale = 0; m_CallbackTable.info (MP4_MSG_TRACK_TIMESCALE, &ts, m_CallbackTable.context); if (m_videoDSILength) m_CallbackTable.putDSI (0, 0, m_videoDSI, m_videoDSILength, ts.videoTimeScale/2, m_CallbackTable.context); for (i=0; i<MP4_MAX_AUDIOTRACKS; i++) { if (m_audioDSILength[i]) m_CallbackTable.putDSI (1 | (i << 8), 0, m_audioDSI[i], m_audioDSILength[i], 0, m_CallbackTable.context); } for (i=0; i<MP4_MAX_SUBPICTRACKS; i++) { if (m_spDSILength[i]) { SPU_DIMENSIONS spDimensions; ASSERT (m_subpiTrackIndex[i] != -1); ASSERT (m_subpiTrackIndex[i] < MP4_MAX_TRACKS); if (m_subpiTrackIndex[i] != -1) { spDimensions.spWidth = m_spWidth[m_subpiTrackIndex[i]]; spDimensions.spHeight = m_spHeight[m_subpiTrackIndex[i]]; m_CallbackTable.info (MP4_MSG_SPU_DIMENSIONS, &spDimensions, m_CallbackTable.context); m_CallbackTable.putDSI (2 | (i << 8), 0, m_spDSI[i], m_spDSILength[i], 0, m_CallbackTable.context); } } else if (i < m_nspStreams) { SPU_DIMENSIONS spDimensions; spDimensions.spWidth = 0; spDimensions.spHeight = 0; m_CallbackTable.info (MP4_MSG_SPU_DIMENSIONS, &spDimensions, m_CallbackTable.context); m_CallbackTable.putDSI (2 | (i << 8), 0, 0, 0, 0, m_CallbackTable.context); } } if (m_videoDSILength) { VIDEO_DIMENSIONS visualDimensions; visualDimensions.visualWidth = m_visualWidth; visualDimensions.visualHeight = m_visualHeight; m_CallbackTable.info (MP4_MSG_VIDEO_DIMENSIONS, &visualDimensions, m_CallbackTable.context); } m_firstVideoChunk = 1; return MP4_ERROR_NO_ERROR;}MP4_ERROR MP4Demux::Schedule (){ RMuint32 error, error0, error1, error2, error3, error4, error5, error6; switch (m_State) { case MP4_DEMUX_STATE_GET_DATA: ASSERT (m_pData == 0); if (m_CallbackTable.getData (&m_pData, &m_DataLength, m_CallbackTable.context) == 0) { m_CallbackTable.addref (m_pData, m_CallbackTable.context); m_State = MP4_DEMUX_STATE_READ_DATA; } break; case MP4_DEMUX_STATE_READ_DATA: ASSERT (m_pData); ASSERT (m_DataLength); ASSERT (m_currentOffset == m_CallbackTable.ftell (m_handle, m_CallbackTable.context)); m_mdatLeft = m_mdatpos + m_mdatlength - m_currentOffset; ASSERT ((RMint32)m_mdatLeft >= 0); m_DataLength = MP4_MIN (m_DataLength, m_mdatLeft); m_DataLength = m_CallbackTable.fread (m_handle, m_pData, m_DataLength, m_CallbackTable.context); DEBUGMSG (0, ("m_DataLength = %d\n", (RMint32)m_DataLength)); DEBUGMSG (0, ("m_mdatLeft = %d\n", (RMint32)m_mdatLeft)); if (m_DataLength) { m_pPutData = m_pData; m_DataLeft = m_DataLength; if (m_total_chunk_size) m_State = MP4_DEMUX_STATE_SEND_DATA; else if (m_samples_per_chunk > 0) m_State = MP4_DEMUX_STATE_PARSE_CHUNK; else m_State = MP4_DEMUX_STATE_PARSE_DATA; } else { ASSERT (m_pData); m_CallbackTable.release (m_pData, m_CallbackTable.context); m_pData = 0; m_State = MP4_DEMUX_STATE_END_OF_FILE; return MP4_ERROR_END_OF_FILE; } break; case MP4_DEMUX_STATE_PARSE_DATA: { RMuint32 voffset = m_video_stco.get32 (&error0); // XXX need to change if you want to support more than // 2 audio or 4 sp streams RMuint32 aoffset0 = m_audio_stco[0].get32 (&error1); RMuint32 soffset0 = m_subpi_stco[0].get32 (&error2); RMuint32 aoffset1 = m_audio_stco[1].get32 (&error3); RMuint32 soffset1 = m_subpi_stco[1].get32 (&error4); RMuint32 soffset2 = m_subpi_stco[2].get32 (&error5); RMuint32 soffset3 = m_subpi_stco[3].get32 (&error6); if (error0 && error1 && error2 && error3 && error4) m_State = MP4_DEMUX_STATE_END_OF_FILE; else if (m_currentOffset == voffset) { DEBUGMSG (0, ("voffset: %d\n", (RMint32)voffset)); RMuint32 first_entry; m_video_stco.advance32 (&error); m_State = MP4_DEMUX_STATE_PARSE_CHUNK; first_entry = m_video_stsc.get32 (&error); if (first_entry == m_video_chunk_index) { m_video_stsc.advance32 (&error); ASSERT (error == 0); m_video_samples_per_chunk = m_video_stsc.get32 (&error); ASSERT (error == 0); DEBUGMSG (0, ("video samples/chunk: %d\n", (RMint32)m_video_samples_per_chunk)); m_video_stsc.advance32 (&error); ASSERT (error == 0); m_video_stsc.get32 (&error); ASSERT (error == 0); m_video_stsc.advance32 (&error); ASSERT (error == 0); } m_video_chunk_index++; m_currentID = 0; m_samples_per_chunk = m_video_samples_per_chunk; DEBUGMSG (0, ("m_video_samples_per_chunk: %d\n", (RMint32)m_video_samples_per_chunk)); ASSERT (m_samples_per_chunk > 0); } else if ((m_currentOffset == aoffset0) || (m_currentOffset == aoffset1)) { RMuint32 aoffset; RMint32 ai; if (m_currentOffset == aoffset0) { aoffset = aoffset0; ai = 0; m_current_au_index = 0; } else { aoffset = aoffset1; ai = 1; m_current_au_index = 1; } DEBUGMSG (0, ("aoffset: %d\n", (RMint32)aoffset)); RMuint32 first_entry; m_audio_stco[ai].advance32 (&error); m_State = MP4_DEMUX_STATE_PARSE_CHUNK; first_entry = m_audio_stsc[ai].get32 (&error); if (first_entry == m_audio_chunk_index[ai]) { m_audio_stsc[ai].advance32 (&error); ASSERT (error == 0); m_audio_samples_per_chunk[ai] = m_audio_stsc[ai].get32 (&error); ASSERT (error == 0); m_audio_stsc[ai].advance32 (&error); ASSERT (error == 0); m_audio_stsc[ai].get32 (&error); ASSERT (error == 0); m_audio_stsc[ai].advance32 (&error); ASSERT (error == 0); } m_audio_chunk_index[ai]++; m_currentID = 1 | (ai << 8); m_samples_per_chunk = m_audio_samples_per_chunk[ai]; DEBUGMSG (0, ("m_audio_samples_per_chunk: %d\n", (RMint32)m_audio_samples_per_chunk)); ASSERT (m_samples_per_chunk > 0); } else if ((m_currentOffset == soffset0) || (m_currentOffset == soffset1) || (m_currentOffset == soffset2) || (m_currentOffset == soffset3)) { RMuint32 soffset; RMint32 si; if (m_currentOffset == soffset0) { soffset = soffset0; si = 0; m_current_sp_index = 0; } else if (m_currentOffset == soffset1) { soffset = soffset1; si = 1; m_current_sp_index = 1; } else if (m_currentOffset == soffset2) { soffset = soffset2; si = 2; m_current_sp_index = 2; } else if (m_currentOffset == soffset3) { soffset = soffset3; si = 3; m_current_sp_index = 3; } DEBUGMSG (0, ("soffset: %d\n", (RMint32)soffset)); RMuint32 first_entry;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -