📄 play_avi_push.c
字号:
for (i=0 ; i<audioInstances ; i++) { DCCMultipleAudioSourceGetSingleDecoderHandleForInstance(avi_info->dcc_info->pMultipleAudioSource, i, &audioHandle); e.ModuleID = audioHandle.moduleID; e.Mask = RUAEVENT_INBAND_COMMAND; /* struct e is already set */ RUAResetEvent(avi_info->pRUA, &e); InbandCmd.Tag = EMhwlibInbandCommand_EOS | INBAND_COMMAND_TYPE_BYTECOUNT | INBAND_COMMAND_NO_COORDINATE; InbandCmd.Tag |= INBAND_COMMAND_DEST_AUDIO | INBAND_COMMAND_ACTION_STOP; InbandCmd.Coordinate = 0; RUASetProperty(avi_info->pRUA, audioHandle.moduleID, RMGenericPropertyID_InbandCommand, &InbandCmd, sizeof(InbandCmd), 0); } avi_info->switching_audio = TRUE; } } if ((actions.cmd == RM_DUALMODE_CHANGE) && (!actions.cmdProcessed)) { RMuint32 i; fprintf(stderr, "Changing DualMode to :"); switch(audio_opt[0].OutputDualMode) { case DualMode_LeftMono: fprintf(stderr, " RightMono\n"); audio_opt[0].OutputDualMode = DualMode_RightMono; break; case DualMode_RightMono: fprintf(stderr, " MixMono\n"); audio_opt[0].OutputDualMode = DualMode_MixMono; break; case DualMode_MixMono: fprintf(stderr, " Stereo\n"); audio_opt[0].OutputDualMode = DualMode_Stereo; break; case DualMode_Stereo: fprintf(stderr, " LeftMono\n"); audio_opt[0].OutputDualMode = DualMode_LeftMono; break; default: fprintf(stderr, " Unknown dual mode\n"); break; } for (i=0; i < audioInstances; i++) { audio_opt[i].OutputDualMode = audio_opt[0].OutputDualMode; err = apply_audio_decoder_options_onthefly(avi_info->dcc_info, &(audio_opt[i])); if (RMFAILED(err)) { fprintf(stderr, "Error applying audio decoder options on the fly %d\n", err); } } actions.cmdProcessed = TRUE; } if (actions.toDoActions & RM_PSM_NORMAL_PLAY) { if (play_opt->fast_audio_recovery) { RMuint64 wantedTime; RMuint64 videoPTS = 0; if (avi_info->dcc_info->SurfaceID != 0) { err = RUAGetProperty(avi_info->pRUA, avi_info->dcc_info->SurfaceID, RMGenericPropertyID_CurrentDisplayPTS, &videoPTS, sizeof(videoPTS)); if (err != RM_OK) { RMDBGLOG((ENABLE, "error %d while getting CurrentDisplayPTS\n", err)); return LABEL_ERROR; } } if (avi_info->vopTimeIncrementResolution == 90000) videoPTS *= 2; RMDBGLOG((ENABLE, "videoPTS %llu / %llu\n", videoPTS, (RMuint64)avi_info->vopTimeIncrementResolution)); wantedTime = (RMuint64)(videoPTS*1000000)/avi_info->vopTimeIncrementResolution; RMDBGLOG((ENABLE, ">> seeking to %llu us to recover audio faster\n", wantedTime)); err = local_seek(avi_info, wantedTime); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Cannot seek to current display time\n")); return LABEL_ERROR; } RM_PSM_SetState(avi_info->PSMcontext, &(avi_info->dcc_info), RM_PSM_Playing); return (RMFAILED(err)) ? LABEL_ERROR : LABEL_STOP; } actions.toDoActions &= ~RM_PSM_NORMAL_PLAY; } return LABEL_NONE;}static void check_prebuf_state(struct avi_context *avi_info, RMuint32 buffersize){ RMbool quit_prebuf = FALSE; enum RM_PSM_State PlaybackStatus = RM_PSM_GetState(avi_info->PSMcontext, &(avi_info->dcc_info)); if (PlaybackStatus != RM_PSM_Prebuffering) return; /* if fail in getbuffer force quitting prebuffering state */ if (buffersize == 0) { RMDBGLOG((ENABLE, "1\n")); quit_prebuf = TRUE; } else if ((play_opt->prebuf_max > 0) && (avi_info->prebuf_level >= play_opt->prebuf_max)) { RMDBGLOG((ENABLE, "2\n")); quit_prebuf = TRUE; } avi_info->prebuf_level += buffersize; if (quit_prebuf) { monitorFIFO(avi_info, TRUE); RMDBGLOG((ENABLE, "exit prebuffering state\n")); RMDBGLOG((ENABLE, "setting play state\n")); fprintf(stderr, "now playing\n"); RM_PSM_SetState(avi_info->PSMcontext, &(avi_info->dcc_info), RM_PSM_Playing); Play(avi_info, RM_DEVICES_AUDIO | RM_DEVICES_VIDEO | RM_DEVICES_STC, DCCVideoPlayFwd); }}static void checkInterleavedCallback (RMuint8 chunkid[4], RMuint8 *chunk, RMuint32 chunkLength, RMuint32 flags, void *context){ struct avi_interleaved_context *interleaved_info = (struct avi_interleaved_context*)context; if ((chunkid[2] == 'd') && ((chunkid[3] == 'c') || (chunkid[3] == 'b'))){ interleaved_info->video_chunks++; } else if ((chunkid[2] == 'w') && (chunkid[3] == 'b')){ interleaved_info->audio_chunks++; }}/* read some chunks from the beginning of the movi * if we find audio and video chunks in the first quarter * (or the first 1MB, whaterver comes first) * we decide that the file is interleaved */static RMbool check_interleaved(struct avi_context *avi_info){ RMuint8 *buf; RMuint32 parsed_bytes = 0, max_parsed_bytes; RMuint32 buf_size = (RMuint32) (1<<play_opt->dmapool_log2size); RMuint32 movi_offset, movi_size; RMstatus err; struct avi_interleaved_context interleaved_context; err = RMAviPushGetMoviOffset(avi_info->pAvi, &movi_offset); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Cannot get movi offset\n")); return FALSE; } err = RMAviPushGetMoviSize(avi_info->pAvi, &movi_size); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Cannot get movi size\n")); return FALSE; } err = RMSeekFile(avi_info->avi_file, movi_offset, RM_FILE_SEEK_START); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Error seeking file to movi\n")); return FALSE; } RMAviPushInitDemuxMovi (avi_info->pAvi, checkInterleavedCallback, NULL); interleaved_context.audio_chunks = 0; interleaved_context.video_chunks = 0; while (RUAGetBuffer(avi_info->pDMA, &buf, COMMON_TIMEOUT_US) != RM_OK) { RMDBGLOG((ENABLE, "Cannot get buffer for interleaved detection\n")); } max_parsed_bytes = RMmin(1024*1024, movi_size/4); while(parsed_bytes < max_parsed_bytes){ RMuint32 count; err = RMReadFile(avi_info->avi_file, buf, buf_size, &count); if (RMFAILED(err)) { break; } RMAviPushDemuxMovi(avi_info->pAvi, buf, count, &interleaved_context); parsed_bytes += count; } RUAReleaseBuffer(avi_info->pDMA, buf); RMDBGLOG((ENABLE, "demuxed %lu bytes and found %lu audio chunks and %lu video chunks\n", parsed_bytes, interleaved_context.audio_chunks, interleaved_context.video_chunks)); if((interleaved_context.audio_chunks) && (interleaved_context.video_chunks)){ fprintf(stderr, "File does not have the interleaved flag but seems to be interleaved.\n"); return TRUE; } else return FALSE;}#define DONT_SCALE_AUDIO_PTS 0static void moviDemuxCallback (RMuint8 chunkid[4], RMuint8 *chunk, RMuint32 chunkLength, RMuint32 flags, void *context){ struct avi_context *avi_info = (struct avi_context *) context; RMuint32 decoder = 0; RMstatus err; struct emhwlib_info Info = {0,}; enum RM_PSM_State FSMstate; RMbool isAudio = FALSE;#ifdef _DEBUG RMint64 diffPTS = 0;#endif RMDBGLOG((DISABLE, "chunk '%c%c%c%c' size %lu flags(%s%s)\n", chunkid[0], chunkid[1], chunkid[2], chunkid[3], chunkLength, flags & RMAVI_FLAG_CHUNK_START ? "chunkStart ":"", flags & RMAVI_FLAG_CHUNK_END ? "chunkEnd":"")); if (avi_info->quitCallback) return; if ((avi_info->iframe) && (avi_info->video_end)) return; FSMstate = RM_PSM_GetState(avi_info->PSMcontext, &(avi_info->dcc_info)); if ((chunkid[2] == 'd') && ((chunkid[3] == 'c') || (chunkid[3] == 'b'))){ RMDBGLOG((AVIDBG, "RECEIVED VIDEO CHUNK (size = %lu)!!!\n", chunkLength)); decoder = avi_info->dcc_info->video_decoder; if (flags & RMAVI_FLAG_CHUNK_START) { Info.ValidFields = (play_opt->send_video_pts) ? TIME_STAMP_INFO : 0; Info.TimeStamp = (RMuint64)(avi_info->videoFrameCounter) * avi_info->vopTimeIncrement; avi_info->videoPTS = Info.TimeStamp; RMDBGLOG((AVIDBG, "Sending video PTS = %llu\n", Info.TimeStamp)); /* in rewind, can be ++ here since it is overwritten in the main loop */ avi_info->videoFrameCounter++; } if (flags & RMAVI_FLAG_CHUNK_END) { avi_info->video_end = TRUE; }#ifdef _DEBUG if (avi_info->currentAudioIndex != -1) { diffPTS = (RMint64) ((avi_info->videoPTS * 1000) / avi_info->vopTimeIncrementResolution);#if DONT_SCALE_AUDIO_PTS diffPTS -= (RMint64) ((avi_info->audio_info[avi_info->currentAudioIndex].audioPTS * 1000) / avi_info->audio_info[avi_info->currentAudioIndex].audioTimeScale);#else diffPTS -= (RMint64) ((avi_info->audio_info[avi_info->currentAudioIndex].real_audio_pts * 1000) / avi_info->audio_info[avi_info->currentAudioIndex].audio_base);#endif }#endif if (play_opt->send_video) avi_info->sendVideoData = TRUE; } else if ((chunkid[2] == 'w') && (chunkid[3] == 'b')){ RMint32 streamID; RMuint32 i; RMDBGLOG((AVIDBG, "RECEIVED AUDIO CHUNK (size = %lu)!!!\n", chunkLength)); isAudio = TRUE; streamID = (chunkid[0]-'0')*10+chunkid[1]-'0'; for (i=0 ; i<avi_info->audio_stream_count ; i++) { if (streamID == avi_info->audio_info[i].streamID) break; } if (i == avi_info->audio_stream_count) { RMDBGLOG((ENABLE, "Invalid audio chunk ID %ld\n", streamID)); return; } if (avi_info->audio_info[i].skipBogusAudioChunk){ RMDBGLOG((AVIDBG, "Skip Bogus MP3 frame\n")); if (flags & RMAVI_FLAG_CHUNK_END) avi_info->audio_info[i].skipBogusAudioChunk = FALSE; return; } err = dump_data_into_file(play_opt, RMVDEMUX_AUDIO, chunk, chunkLength, 0, FALSE, FALSE); if (err != RM_OK) { RMDBGLOG((ENABLE, "Cannot dump audio \n")); } Info.TimeStamp = avi_info->audio_info[i].audioPTS; // scale PTS to audio_base if (avi_info->audio_info[i].audioTimeScale) { RMuint64 pts = Info.TimeStamp; if (pts < 0x8000000000000000ll) { pts *= avi_info->audio_info[i].audio_base; pts /= avi_info->audio_info[i].audioTimeScale; } else { pts /= avi_info->audio_info[i].audioTimeScale; pts *= avi_info->audio_info[i].audio_base; }#if DONT_SCALE_AUDIO_PTS RMDBGLOG((DISABLE, "should have scaled pts %llu with %lu/%lu => %llu\n", Info.TimeStamp, avi_info->audio_info[i].audio_base, avi_info->audio_info[i].audioTimeScale, pts));#else RMDBGLOG((DISABLE, "scale pts %llu with %lu/%lu => %llu\n", Info.TimeStamp, avi_info->audio_info[i].audio_base, avi_info->audio_info[i].audioTimeScale, pts)); Info.TimeStamp = pts;#endif // we have to store it for the diffPTS when processing video payload avi_info->audio_info[i].real_audio_pts = Info.TimeStamp; }#ifdef _DEBUG if (avi_info->currentAudioIndex != -1) { diffPTS = (RMint64) ((avi_info->videoPTS * 1000) / avi_info->vopTimeIncrementResolution);#if DONT_SCALE_AUDIO_PTS diffPTS -= (RMint64) ((avi_info->audio_info[avi_info->currentAudioIndex].audioPTS * 1000) / avi_info->audio_info[avi_info->currentAudioIndex].audioTimeScale);#else diffPTS -= (RMint64) ((Info.TimeStamp * 1000) / avi_info->audio_info[avi_info->currentAudioIndex].audio_base);#endif }#endif avi_info->audio_info[i].audioByteCounter += chunkLength; if (flags & RMAVI_FLAG_CHUNK_START){ avi_info->audio_info[i].audioFrameCounter++; Info.ValidFields = (play_opt->send_audio_pts) ? TIME_STAMP_INFO : 0; if (avi_info->audio_info[i].audio_VBR){ /* Some streams have junk audio chunks at the beginning, skip them (see * Sweet.Home.Alabama.DVDRip.avi). A junk chunk size is always a multiple of nBlockAlign, * it is filled with zeros (another thing we chould check, but it would be slower) */ if (chunkLength % avi_info->audio_info[i].audioFormat.nBlockAlign == 0){ RMDBGLOG((ENABLE,"Discard junk audio chunk (%ld frames)\n", chunkLength / avi_info->audio_info[i].audioFormat.nBlockAlign)); if (!(flags & RMAVI_FLAG_CHUNK_END)) avi_info->audio_info[i].skipBogusAudioChunk = TRUE; avi_info->audio_info[i].audioPTS += chunkLength; return; } else avi_info->audio_info[i].audioPTS += avi_info->audio_info[i].audioFormat.nBlockAlign; } } if (!avi_info->audio_info[i].audio_VBR){ avi_info->audio_info[i].audioPTS = ((RMuint64)(avi_info->audio_info[i].audioByteCounter) * avi_info->audio_info[i].audioTimeScale) / avi_info->audio_info[i].audioFormat.nAvgBytesPerSec; } if (streamID!=(RMint32) avi_info->currentAudioStream) return; /* compute PTS but do not send data */ if ((FSMstate != RM_PSM_Playing) && (FSMstate != RM_PSM_Paused) && (FSMstate != RM_PSM_Prebuffering)) return; if (avi_info->dcc_info->pMultipleAudioSource) { struct DCCAudioSourceHandle audioHandle; /* get only first decoder */ DCCMultipleAudioSourceGetSingleDecoderHandleForInstance(avi_info->dcc_info->pMultipleAudioSource, 0, &audioHandle); decoder = audioHandle.moduleID; //avi_info->dcc_info->audio_decoder; RMDBGLOG((AVIDBG, "Audio PTS=%llu byte count = %ld\n", avi_info->audio_info[i].audioPTS, avi_info->audio_info[i].audioByteCounter)); } if ((!avi_info->need_audio_au) || (flags & RMAVI_FLAG_CHUNK_START)) avi_info->sendAudioData = TRUE; } else if ((chunkid[2] == 'd') && (chunkid[3] == 'd')){ RMDBGLOG((AVIDBG, "RECEIVED DRM CHUNK !!!\n")); return; } else { RMDBGLOG((DISABLE, "UNKNOWN CHUNK %c%c%c%c\n",chunkid[0], chunkid[1], chunkid[2], chunkid[3])); return; }#ifdef _DEBUG if ((play_opt->send_audio) && (play_opt->send_video)) { if (diffPTS > avi_info->max_diff) { avi_info->max_diff = diffPTS; if (FSMstate == RM_PSM_Playing) { RMDBGLOG((ENABLE, "[V-A] %ld ms\n", (RMint32) diffPTS)); } } else if (diffPTS < avi_info->min_diff) { avi_info->min_diff = diffPTS; if (FSMstate == RM_PSM_Playing) { RMDBGLOG((ENABLE, "[V-A] %ld ms\n", (RMint32) diffPTS));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -