?? play_mp4.c
字號:
goto mainloop_noseek; \ case LABEL_START_SENDING_DATA: \ goto start_sending_data; \ case LABEL_SIGNAL_EOS_AND_EXIT: \ goto signal_EOS_and_exit_loop; \ case LABEL_NONE: \ RMDBGLOG((ENABLE, "warning unrecognised key pressed\n"));\ break; \ } \ } \} while(0)#define ADTS_HEADER_SIZE 7static RMuint32 FindAdtsSRIndex(RMuint32 sr){ const RMuint32 adts_sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,7350,0,0,0}; RMuint32 i; for (i = 0; i < 16; i++) { if (sr == adts_sample_rates[i]) return i; } return 0xf;}static void FillAdtsHeader(RMuint8 *buf, RMuint32 framesize, RMuint32 samplerate, RMuint32 channelcount, RMuint32 objectID){ RMuint32 profile = (objectID - 1) & 0x3; RMuint32 sr_index = FindAdtsSRIndex(samplerate); framesize += ADTS_HEADER_SIZE; /* add adts header size */ buf[0] = 0xFF; /* 8b: syncword */ buf[1] = 0xF1; /* 4b: syncword */ /* 1b: mpeg id = 0 */ /* 2b: layer = 0 */ /* 1b: protection absent = 1 */ buf[2] = ((profile << 6) & 0xC0); /* 2b: profile */ buf[2] += ((sr_index << 2) & 0x3C); /* 4b: sampling_frequency_index */ /* 1b: private = 0 */ buf[2] += ((channelcount >> 2) & 0x1); /* 1b: channel_configuration */ buf[3] = ((channelcount << 6) & 0xC0); /* 2b: channel_configuration */ /* 1b: original = 0 */ /* 1b: home = 0 */ /* 1b: copyright_id = 0 */ /* 1b: copyright_id_start = 0 */ buf[3] += ((framesize >> 11) & 0x3); /* 2b: aac_frame_length */ buf[4] = ((framesize >> 3) & 0xFF); /* 8b: aac_frame_length */ buf[5] = ((framesize << 5) & 0xE0); /* 3b: aac_frame_length */ buf[5] += ((0x7FF >> 6) & 0x1F); /* 5b: adts_buffer_fullness */ buf[6] = ((0x7FF << 2) & 0xFC); /* 6b: adts_buffer_fullness */ /* 2b: num_raw_buf_blocks = 0 */}/* prototypes */static RMuint64 round_int_div(RMuint64 numerator, RMuint32 divisor);static RMstatus mp4_select_audio_track(struct SendMP4DataContext *pSendContext, RMuint32 index);static RMstatus mp4_select_spu_track(struct SendMP4DataContext *pSendContext, RMuint32 index);static RMstatus mp4_select_subtitle_track(struct SendMP4DataContext *pSendContext, RMuint32 index);static void get_buffer(struct SendMP4DataContext *pSendContext, RMuint8 **buf);RMuint64 round_int_div(RMuint64 numerator, RMuint32 divisor) { RMuint64 temp; temp = numerator / divisor; if ((numerator % divisor) * 2 > divisor) temp++; return temp;}static RMstatus init_private_options(struct priv_cmdline *options){ options->audio_track = 0; options->internal_file_open = 0; options->monitorFIFOs = FALSE; #ifdef WITH_MONO options->spuEnabled = TRUE; options->subtitlesEnabled = TRUE;#else options->spuEnabled = FALSE; options->subtitlesEnabled = FALSE;#endif return RM_OK;}#ifndef WITH_MONOstatic RMstatus parse_private_cmdline(struct SendMP4DataContext *pSendContext, int argc, char **argv, int *index, struct priv_cmdline *options){ RMstatus err = RM_PENDING; int i = *index; if (! strcmp(argv[i], "-at")) { if (argc > i+1) { options->audio_track = strtol(argv[i+1], NULL, 10); i+=2; err = RM_OK; } else err = RM_ERROR; } else if ( ! strcmp(argv[i], "-fopen")) { if (argc > i+1) { options->internal_file_open = strtol(argv[i+1], NULL, 10); i+=2; err = RM_OK; } else err = RM_ERROR; } else if ( ! strcmp(argv[i], "-monitor")) { options->monitorFIFOs = TRUE; err = RM_OK; i++; } else if ( ! strcmp(argv[i], "-subt")) { options->subtitlesEnabled = TRUE; err = RM_OK; i++; } *index = i; return err;}static void show_private_options(void){ fprintf(stderr, "MP4 OPTIONS (default values inside brackets)\n" "\t-at track: Selects audio track number track [0]\n" "\t-spu enable SPU (if present)\n" "\t-subt enable Subtitles (if present)\n" "\t-fopen <0|1>: use internal file open [0]\n");}static void show_usage(char *progname){ show_private_options(); show_playback_options(); show_display_options(); show_video_options(); show_audio_options(); fprintf(stderr, "--------------------------------\n" "Minimum cmd line: %s <file name>\n" "--------------------------------\n", progname); exit(1);}static void parse_cmdline(struct SendMP4DataContext *pSendContext, int argc, char *argv[], RMuint32 *currentAudioInstance){ int i; RMstatus err; if (argc < 2) show_usage(argv[0]); i = 1; while ((argc > i)) { if (argv[i][0] != '-') { if (pSendContext->play_opt->filename == NULL) { pSendContext->play_opt->filename = argv[i]; i++; } else show_usage(argv[0]); } else { err = parse_private_cmdline(pSendContext, argc, argv, &i, &(pSendContext->priv_opt)); if (err == RM_ERROR) show_usage(argv[0]); if (err != RM_PENDING) continue; err = parse_playback_cmdline(argc, argv, &i, pSendContext->play_opt); if (err == RM_ERROR) show_usage(argv[0]); if (err != RM_PENDING) continue; err = parse_display_cmdline(argc, argv, &i, pSendContext->disp_opt); if (err == RM_ERROR) show_usage(argv[0]); if (err != RM_PENDING) continue; err = parse_video_cmdline(argc, argv, &i, pSendContext->video_opt); if (err == RM_ERROR) show_usage(argv[0]); if (err != RM_PENDING) continue; RMDBGLOG((ENABLE, "option[%lu] %s\n", i, argv[i])); err = parse_audio_cmdline2(argc, argv, &i, pSendContext->audio_opt, MAX_AUDIO_DECODER_INSTANCES, currentAudioInstance); if (RMFAILED(err)) show_usage(argv[0]); } } if (pSendContext->play_opt->filename == NULL) show_usage(argv[0]);}#endif //WITH_MONOstatic void check_prebuf_state(struct SendMP4DataContext * pSendContext, RMuint32 buffersize);static RMstatus WaitForEOS(struct SendMP4DataContext *pSendContext, struct RM_PSM_Actions *pActions){ RMuint32 eos_bit_field = 0; enum RM_PSM_State PlaybackStatus = RM_PSM_GetState(pSendContext->PSMcontext, &(pSendContext->dcc_info)); if (pSendContext == NULL || pActions == NULL) return RM_ERROR; if (pSendContext->SendVideoData) eos_bit_field |= EOS_BIT_FIELD_VIDEO; if (pSendContext->SendAudioData && ((PlaybackStatus == RM_PSM_Playing) || (PlaybackStatus == RM_PSM_Prebuffering))) eos_bit_field |= EOS_BIT_FIELD_AUDIO; return WaitForEOSWithCommand(pSendContext->PSMcontext, &(pSendContext->dcc_info), pActions, eos_bit_field);}static RMstatus init_MP4_tracks(struct SendMP4DataContext *pSendContext){ RMuint32 videotrackID = 0; RMstatus status; RMDBGLOG((ENABLE, "initTracks\n"));#if 0 if (!pSendContext->play_opt->send_video) { pSendContext->isAudioOnly = TRUE; pSendContext->videoTracks = 0; goto init_audio_track; }#endif pSendContext->videoTracks = RMGetMP4NumberOfVideoTracks(pSendContext->mp4c); RMDBGLOG((ENABLE, "found %lu video tracks\n", pSendContext->videoTracks)); if (pSendContext->videoTracks > 0) { /* so far, all files have only one video track, init the first video track found */ RMDBGLOG((ENABLE, "init mp4 video track\n")); pSendContext->currentVideoTrack = 1; pSendContext->mp4tV = (ExternalRMmp4Track) NULL; videotrackID = RMGetMP4VideoTrackID(pSendContext->mp4c); pSendContext->videodsiBuf = (RMuint8 *) NULL; if (videotrackID > 0) { RMmpeg4TrackType type; pSendContext->mp4tV = RMOpenMP4Track(pSendContext->mp4c, videotrackID); if (!pSendContext->mp4tV) { RMDBGLOG((ENABLE, "couldnt open track!\n")); goto disable_video; } RMDBGLOG((ENABLE, "video track ID is %lu\n", videotrackID)); RMGetMP4TrackWidth(pSendContext->mp4tV, &(pSendContext->videoWidth)); RMGetMP4TrackHeight(pSendContext->mp4tV, &(pSendContext->videoHeight)); pSendContext->videoWidth >>= 16; pSendContext->videoHeight >>= 16; RMDBGLOG((ENABLE, ">> video size %lu x %lu\n", pSendContext->videoWidth, pSendContext->videoHeight)); RMGetMP4TrackType(pSendContext->mp4tV, &type); if (type == RM_VIDEO_H264_TRACK) pSendContext->isH264 = TRUE; else if (type == RM_VIDEO_MPEG4_TRACK) pSendContext->isH264 = FALSE; else { RMDBGLOG((ENABLE, "unknown video!!\n")); goto disable_video; } if (pSendContext->isH264) { RMuint32 level, profile, lengthSize; RMDBGLOG((ENABLE, ">> video track is H264\n")); RMGetH264Level(pSendContext->mp4tV, &level); RMGetH264Profile(pSendContext->mp4tV, &profile); RMGetH264LengthSize(pSendContext->mp4tV, &lengthSize); pSendContext->h264LengthSize = lengthSize; RMDBGLOG((ENABLE, "level %lu, profile %lu, lengthSize %lu\n", level, profile, lengthSize)); if (level > 41) { fprintf(stderr, "unsupported level, level %lu > max 41\n", level); goto disable_video; } if (profile > 100) { fprintf(stderr, "unsupported profile, profile %lu > max 100\n", profile); goto disable_video; }#ifdef WITH_MONO RMDBGLOG((ENABLE, ">> set codec to H264 HD\n")); pSendContext->video_opt->MPEGProfile = Profile_H264_HD; pSendContext->video_opt->Codec = VideoDecoder_Codec_H264_HD;#endif } else { RMDBGLOG((ENABLE, ">> video track is MPEG4\n"));#ifdef WITH_MONO RMDBGLOG((ENABLE, ">> set codec to MPEG4\n")); pSendContext->video_opt->MPEGProfile = Profile_MPEG4_HD; pSendContext->video_opt->Codec = VideoDecoder_Codec_MPEG4_HD;#endif } pSendContext->videodsiBuf = RMGetMP4TrackDSI(pSendContext->mp4tV, &(pSendContext->videodsiSize)); RMDBGLOG((ENABLE, "got %lu bytes of video DSI, parsing...\n", pSendContext->videodsiSize)); if (pSendContext->videodsiSize > (RMuint32) (1<<pSendContext->dmaBufferSizeLog2)) { RMDBGLOG((ENABLE, "video DSI too big!!\n")); goto disable_video; } else if (pSendContext->videodsiSize == 0) { RMDBGLOG((ENABLE, "video DSI size is zero!!\n")); goto disable_video; } pSendContext->VideoCTSTimeScale = RMGetMP4TrackTimeScale(pSendContext->mp4tV); switch (pSendContext->video_opt->MPEGProfile){ case Profile_FIRST_: case Profile_LAST_: break; case Profile_MPEG2_SD: case Profile_MPEG2_DVD: case Profile_MPEG2_HD: case Profile_MPEG2_SD_Packed: case Profile_MPEG2_HD_Packed: case Profile_MPEG2_DVD_Packed: case Profile_MPEG2_SD_DeInt: case Profile_MPEG2_DVD_DeInt: case Profile_MPEG2_HD_DeInt: case Profile_MPEG2_SD_Packed_DeInt: case Profile_MPEG2_DVD_Packed_DeInt: case Profile_MPEG2_HD_Packed_DeInt: RMDBGLOG((ENABLE, "MPEG 2 video\n")); pSendContext->video_vop_tir = 90000; break; case Profile_DIVX3_SD: case Profile_DIVX3_HD: case Profile_DIVX3_SD_Packed: case Profile_DIVX3_HD_Packed: RMDBGLOG((ENABLE, "DIVX3 video\n")); pSendContext->video_vop_tir = pSendContext->VideoCTSTimeScale; break; case Profile_WMV_SD: case Profile_WMV_816P: case Profile_WMV_HD: RMDBGLOG((ENABLE, "WMV9 video\n")); pSendContext->video_vop_tir = 1000; break; case Profile_MPEG4_SD: case Profile_MPEG4_HD: case Profile_MPEG4_SD_Packed: case Profile_MPEG4_HD_Packed: case Profile_MPEG4_SD_DeInt: case Profile_MPEG4_HD_DeInt: case Profile_MPEG4_SD_Packed_DeInt: case Profile_MPEG4_HD_Packed_DeInt: case Profile_MPEG4_SD_Padding: case Profile_MPEG4_HD_Padding: case Profile_MPEG4_SD_DeInt_Padding: case Profile_MPEG4_HD_DeInt_Padding: RMDBGLOG((ENABLE, "MPEG4 video\n")); ParseMP4VideoDSI(pSendContext->videodsiBuf, pSendContext->videodsiSize, (void *) &pSendContext->video_vop_tir, sizeof(RMuint32)); break; case Profile_VC1_SD: case Profile_VC1_HD: RMDBGLOG((ENABLE, "VC1 video\n")); pSendContext->video_vop_tir = pSendContext->VideoCTSTimeScale; break; case Profile_H264_SD: case Profile_H264_HD: case Profile_H264_SD_DeInt: case Profile_H264_HD_DeInt: RMDBGLOG((ENABLE, "H264 video\n")); pSendContext->video_vop_tir = pSendContext->VideoCTSTimeScale; break; } RMDBGLOG((ENABLE,"********** video VOP TIR %lu, VideoCTSTimeScale %lu\n", pSendContext->video_vop_tir, pSendContext->VideoCTSTimeScale)); if (!pSendContext->video_vop_tir) { RMDBGLOG((ENABLE, "video_vop_tir = 0!!, reset to VideoCTSTimeScale\n")); pSendContext->video_vop_tir = pSendContext->VideoCTSTimeScale; } } else goto disable_video; } else { disable_video: RMDBGLOG((ENABLE, ">> no video\n")); pSendContext->SendVideoData = FALSE; pSendContext->isAudioOnly = TRUE; pSendContext->currentVideoTrack = 0; if (pSendContext->mp4tV) { RMDBGLOG((ENABLE, "closing video track\n")); RMCloseMP4Track(pSendContext->mp4c, pSendContext->mp4tV); pSendContext->mp4tV = (ExternalRMmp4Track) NULL; } } // continue with other tracks#if 0 if (!pSendContext->play_opt->send_audio) goto init_spu_track;#endif RMDBGLOG((ENABLE, "init mp4 audio track(s)\n")); pSendContext->mp4tA = (ExternalRMmp4Track) NULL;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -