📄 play_mp4.c
字号:
else { RMuint32 nextSampleSize; RMGetMP4TrackNextSampleSize(pSendContext->mp4tV, &nextSampleSize); RMDBGLOG((H264_SC_DBG, "%02x %02x %02x %02x this sample size %6lu next %6lu flags %2lu\n", sample->buf[0], sample->buf[1], sample->buf[2], sample->buf[3], sample->size, nextSampleSize, sample->flags)); } if (sample->flags & MP4_AU_START) { pSendContext->h264sendStartCode = TRUE; pSendContext->h264readPacketSize = TRUE; /* clear the flag because if sending part of the sample returns pending, we'll get called again and we shouldn't send the startcode again */ sample->flags &= ~MP4_AU_START; } while (sample->size) { RMuint32 sizeToSend; RMDBGLOG((H264_SC_DBG, "available buffer count: %lu\n", RUAGetAvailableBufferCount(pSendContext->pDMA))); // send startcode if (pSendContext->h264sendStartCode) { // get a DMA buffer if (!pSendContext->startCodeDMABuffer) { get_buffer(pSendContext, &(pSendContext->startCodeDMABuffer)); if (pSendContext->processKeyResultValid) { RMDBGLOG((ENABLE, "a key was pressed during H264 startcode buffer wait")); // a key was pressed, return to main_loop to process it return RM_PENDING; } pSendContext->startCodeDMABufferOffset = 0; RMDBGLOG((DBG, "setting new buffer for video startcodes 0x%lx\n", (RMuint32)pSendContext->startCodeDMABuffer)); } videoDMAStartCodeBuffer = pSendContext->startCodeDMABuffer + pSendContext->startCodeDMABufferOffset; pSendContext->videoTransferPending = FALSE; // set StartCode (4bytes) RMuint32ToBeBuf(0x00000001, videoDMAStartCodeBuffer); if (pSendContext->SendVideoData) { // send startcode with PTS from the sample while (1) { status = RUASendData(pSendContext->pRUA, pSendContext->dcc_info->video_decoder, pSendContext->pDMA, videoDMAStartCodeBuffer, 4, &pSendContext->video_Info, sizeof(pSendContext->video_Info)); if (status == RM_OK) break; /* handle end of prebufferisation here */ else if (status == RM_PENDING) { struct RUAEvent e; check_prebuf_state(pSendContext, 0); e.ModuleID = pSendContext->dcc_info->video_decoder; e.Mask = RUAEVENT_XFER_FIFO_READY; RUAWaitForMultipleEvents(pSendContext->pRUA, &e, 1, COMMON_TIMEOUT_US, NULL); RMDBGLOG((ENABLE, "waiting to send video startcode\n")); } else { RMDBGLOG((ENABLE, "waiting to send video startcode\n")); return status; } } } status = dump_data_into_file(pSendContext->play_opt, RMVDEMUX_VIDEO, videoDMAStartCodeBuffer, 4, pSendContext->video_Info.TimeStamp, (pSendContext->video_Info.ValidFields & TIME_STAMP_INFO), pSendContext->video_Info.FirstAccessUnitPointer); if (RMFAILED(status)) { RMDBGLOG((ENABLE, "Cannot dump data %d\n", status)); return status; } pSendContext->h264sendStartCode = FALSE; // required for prebuffering routine pSendContext->videoDataSent += 4; pSendContext->videoBitrateCounter += 4 * 8; pSendContext->startCodeDMABufferOffset += 4; if (pSendContext->startCodeDMABufferOffset + DMABUFFER_UNUSED_BLOCK_SIZE >= sizeBuffer) { RMDBGLOG((DBG, "release buffer 0x%lx startcode %lu\n", (RMuint32)pSendContext->startCodeDMABuffer, pSendContext->startCodeDMABufferOffset)); RUAReleaseBuffer(pSendContext->pDMA, pSendContext->startCodeDMABuffer); pSendContext->startCodeDMABuffer = NULL; pSendContext->startCodeDMABufferOffset = 0; } RMDBGLOG((H264_SC_DBG, "sent startcode\n")); if (pSendContext->SendVideoData) { RMDBGLOG((SENDDBG, "sent H264 video startcode : frameCount %lu totalBytes %lu pts %lld ( 0x%llx ) %s\n", pSendContext->videoFrameCount, pSendContext->videoDataSent, pSendContext->video_Info.TimeStamp, pSendContext->video_Info.TimeStamp, (pSendContext->video_Info.ValidFields & TIME_STAMP_INFO) ? "valid":"")); } // dont send pts with subsequent packets pSendContext->video_Info.ValidFields = 0; pSendContext->video_Info.TimeStamp = 0; } // read avcPkt size if (pSendContext->h264readPacketSize) { while (sample->size) { *(pSendContext->h264PktLenBuf) = *(sample->buf); pSendContext->h264PktLenBuf++; sample->size--; sample->buf++; pSendContext->h264LengthSize--; if (!pSendContext->h264LengthSize) break; } if (!pSendContext->h264LengthSize) { pSendContext->h264readPacketSize = FALSE; RMGetH264LengthSize(pSendContext->mp4tV, &(pSendContext->h264LengthSize)); pSendContext->h264PktLenBuf -= pSendContext->h264LengthSize; switch (pSendContext->h264LengthSize) { case 2: pSendContext->h264PktLen = RMbeBufToUint16(pSendContext->h264PktLenBuf); break; case 3: pSendContext->h264PktLen = RMbeBufToUint24(pSendContext->h264PktLenBuf); break; case 4: pSendContext->h264PktLen = RMbeBufToUint32(pSendContext->h264PktLenBuf); break; default: RMDBGLOG((ENABLE, "ERROR! unhandled h264LengthSize %lu\n", pSendContext->h264LengthSize)); return RM_ERROR; } RMDBGLOG((H264_SC_DBG, "read h264 packet size %lu (0x%lx)\n", pSendContext->h264PktLen, pSendContext->h264PktLen)); pSendContext->h264BytesLeft = pSendContext->h264PktLen; } if (!sample->size) { RMDBGLOG((ENABLE, "get new sample\n")); return RM_OK; } } // send the rest of the buffer sizeToSend = RMmin(pSendContext->h264BytesLeft, sample->size); if (pSendContext->SendVideoData) { status = RUASendData(pSendContext->pRUA, pSendContext->dcc_info->video_decoder, pSendContext->pDMA, sample->buf, sizeToSend, &pSendContext->video_Info, sizeof(pSendContext->video_Info)); if (status != RM_OK) { if (status == RM_PENDING) { RMDBGLOG((ENABLE, "video transfer pending\n")); pSendContext->videoTransferPending = TRUE; } return status; } pSendContext->videoTransferPending = FALSE; } status = dump_data_into_file(pSendContext->play_opt, RMVDEMUX_VIDEO, sample->buf, sizeToSend, pSendContext->video_Info.TimeStamp, (pSendContext->video_Info.ValidFields & TIME_STAMP_INFO), pSendContext->video_Info.FirstAccessUnitPointer); if (RMFAILED(status)) { RMDBGLOG((ENABLE, "Cannot dump data %d\n", status)); } pSendContext->h264BytesLeft -= sizeToSend; sample->size -= sizeToSend; sample->buf += sizeToSend; // required for prebuffering routine pSendContext->videoDataSent += sizeToSend; pSendContext->videoBitrateCounter += sizeToSend * 8; RMDBGLOG((H264_SC_DBG, "send payload (%5lu/%5lu), sampleSize %5lu, bytesLeft %5lu\n", sizeToSend, pSendContext->h264PktLen, sample->size, pSendContext->h264BytesLeft)); if (!pSendContext->h264BytesLeft) { pSendContext->h264sendStartCode = TRUE; pSendContext->h264readPacketSize = TRUE; } if (pSendContext->SendVideoData) { RMDBGLOG((SENDDBG, "sent a video packet (flags %lu) frameCount %lu size %ld / %lu (total %lu ) pts %lld ( 0x%llx ) %s\n", pSendContext->videosample.flags, pSendContext->videoFrameCount, sizeToSend, pSendContext->videoSampleSize, pSendContext->videoDataSent, pSendContext->video_Info.TimeStamp, pSendContext->video_Info.TimeStamp, (pSendContext->video_Info.ValidFields & TIME_STAMP_INFO) ? "valid":"")); } } return RM_OK; } // else, just send the packets coming from the MP4 parser if (pSendContext->SendVideoData) { status = RUASendData(pSendContext->pRUA, pSendContext->dcc_info->video_decoder, pSendContext->pDMA, pSendContext->videosample.buf, pSendContext->videosample.size, &pSendContext->video_Info, sizeof(pSendContext->video_Info)); if (status != RM_OK) { if (status == RM_PENDING) { RMDBGLOG((ENABLE, "video transfer pending\n")); pSendContext->videoTransferPending = TRUE; } return status; } pSendContext->videoTransferPending = FALSE; } status = dump_data_into_file(pSendContext->play_opt, RMVDEMUX_VIDEO, pSendContext->videosample.buf, pSendContext->videosample.size, pSendContext->video_Info.TimeStamp, (pSendContext->video_Info.ValidFields & TIME_STAMP_INFO), pSendContext->video_Info.FirstAccessUnitPointer); if (RMFAILED(status)) { RMDBGLOG((ENABLE, "Cannot dump data %d\n", status)); } { RMuint8 picType = 0xFF; // check MPEG4 picture type, 0=I;1=P;2=B;3=S if ((pSendContext->videosample.size > 5) && (!pSendContext->isH264)) { RMuint8 *dummy = pSendContext->videosample.buf; RMuint8 byte; if ((dummy[0] == 0) && (dummy[1] == 0) && (dummy[2] == 1) && (dummy[3] == 0xb6)) { byte = dummy[4]; byte &= 0xC0; byte >>= 6; picType = byte; } } if (pSendContext->SendVideoData) { RMDBGLOG((SENDDBG, "sent a packet video %s dma 0x%08X, sample 0x%08X, size %ld, total %lu, pts %lld(0x%llx) %s\n", (picType == 0) ? "(picType: I)": ((picType == 1) ? "(picType: P)": ((picType == 2) ? "(picType: B)":"")), pSendContext->pDMA, pSendContext->videosample.buf, pSendContext->videosample.size, pSendContext->videoDataSent, pSendContext->video_Info.TimeStamp, pSendContext->video_Info.TimeStamp, (pSendContext->video_Info.ValidFields & TIME_STAMP_INFO) ? "valid":"")); } } // required for prebuffering routine pSendContext->videoDataSent += pSendContext->videosample.size; pSendContext->videoBitrateCounter += pSendContext->videosample.size * 8; return RM_OK;}static RMstatus send_MP4_video(struct SendMP4DataContext * pSendContext){ RMstatus status; RMuint64 pts; RMbool notEOS = TRUE; //enum RM_PSM_State PlaybackStatus = RM_PSM_GetState(pSendContext->PSMcontext, &(pSendContext->dcc_info)); if (pSendContext->videoTransferPending) goto send_data; pSendContext->videosample.buf = pSendContext->videoDMABuffer + pSendContext->videoDMABufferOffset; pSendContext->videosample.size = (1<<pSendContext->dmaBufferSizeLog2) - pSendContext->videoDMABufferOffset; if (pSendContext->play_opt->disk_ctrl_state == DISK_CONTROL_STATE_SLEEPING) RMDBGLOG((ENABLE, "trying to read from a suspended drive!!\n")); if (pSendContext->isIFrameMode && pSendContext->IFrameDirection > 0) { notEOS = RMGetNextMP4RandomAccessSample(pSendContext->mp4tV, &(pSendContext->videosample), pSendContext->videosample.size); } else if (pSendContext->isIFrameMode && pSendContext->IFrameDirection < 0) { notEOS = RMGetPrevMP4RandomAccessSample(pSendContext->mp4tV, &(pSendContext->videosample), pSendContext->videosample.size); } else notEOS = RMGetNextMP4Sample(pSendContext->mp4tV, &(pSendContext->videosample), pSendContext->videosample.size); if (!notEOS) { RMDBGLOG((ENABLE,"Failed to get Video sample -> end of video stream\n")); pSendContext->videoEOS = TRUE; return RM_EOS; } RMDBGLOG((DISABLE, "got video sample of size %ld\n", pSendContext->videosample.size)); pSendContext->videoSampleSize = pSendContext->videosample.size; pSendContext->video_Info.TimeStamp = 0; pSendContext->video_Info.ValidFields = 0; if (pSendContext->videosample.flags & MP4_AU_START) { pSendContext->videoFrameCount++; } //RMDBGLOG((ENABLE, "[%lu] sample size %lu flags %lu\n", pSendContext->videoFrameCount, pSendContext->videoSampleSize, pSendContext->videosample.flags)); if (pSendContext->videosample.flags & MP4_CTS_VALID) { pSendContext->video_Info.ValidFields = TIME_STAMP_INFO; if (pSendContext->videosample.DTS_MSB != pSendContext->videosample.CTS_MSB) { RMuint64 dts; RMuint64 cts; RMint32 diff = 0; // this is a hack for some h264 mov files which contain "invalid" pts // bug #5606 // some debug: dts = (RMuint64)pSendContext->videosample.DTS_MSB; dts <<= 32; dts |= pSendContext->videosample.DTS_LSB; cts = (RMuint64)pSendContext->videosample.CTS_MSB; cts <<= 32; cts |= pSendContext->videosample.CTS_LSB; RMDBGLOG((DISABLE, "invalid pts from CTS. DTSh %08lx DTSl %08lx = %09llx CTSh %08lx CTSl %08lx = %09llx lastPTS %llx scale %lu\n", pSendContext->videosample.DTS_MSB, pSendContext->videosample.DTS_LSB, dts, pSendContext->videosample.CTS_MSB, pSendContext->videosample.CTS_LSB, cts, pSendContext->lastVideoPTS, pSendContext->video_vop_tir)); /* the hack: if following condition is satisfied, compute a pts from emulated CTS where emulated CTS = DTS + diff and diff = CTS_LSB - DTS_LSB (just to make sure delay between DTS and CTS is respected in final pts */ if ((pSendContext->videosample.DTS_MSB == 0) && (pSendContext->videosample.CTS_MSB == 1)) diff = pSendContext->videosample.CTS_LSB - pSendContext->videosample.DTS_LSB; // emulated cts cts = (RMuint64)pSendContext->videosample.DTS_MSB; cts <<= 32; cts |= pSendContext->videosample.DTS_LSB + diff ; RMDBGLOG((DISABLE, "send pts based on emulated CTS: DTSh %08lx DTSl %08lx -> 0x%09llx\n", pSendContext->videosample.DTS_MSB, pSendContext->videosample.DTS_LSB + diff, cts)); pts = RMuint64from2RMuint32(pSendContext->videosample.DTS_MSB, pSendContext->videosample.DTS_LSB + diff); } else pts = RMuint64from2RMuint32(pSendContext->videosample.CTS_MSB, pSendContext->videosample.CTS_LSB); pSendContext->video_Info.TimeStamp = pts; if (pSendContext->video_vop_tir != pSendContext->VideoCTSTimeScale) { pSendContext->video_Info.TimeStamp = round_int_div(pts * pSendContext->video_vop_tir, pSendContext->VideoCTSTimeScale); RMDBGLOG((DISABLE, "video pts scaling! old %lld => %lld thru a factor %ld/%ld\n", pts, pSendContext->video_Info.TimeStamp, pSendContext->video_vop_tir, pSendContext->VideoCTSTimeScale)); } else RMDBGLOG((DISABLE, "setting pts
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -