📄 media_source.cpp
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is MPEG4IP. * * The Initial Developer of the Original Code is Cisco Systems Inc. * Portions created by Cisco Systems Inc. are * Copyright (C) Cisco Systems Inc. 2000-2002. All Rights Reserved. * * Contributor(s): * Dave Mackie dmackie@cisco.com */#include "mp4live.h"#include "media_source.h"#include "audio_encoder.h"#include "video_encoder.h"#include "video_util_rgb.h"#include <mp4av.h>#include "mpeg4ip_byteswap.h"//#define DEBUG_AUDIO_RESAMPLER 1//#define DEBUG_SYNC 1//#define DEBUG_SYNC_DRIFT 1//#define DEBUG_SYNC_DROPS 1//#define DEBUG_SYNC_LAG 1CMediaSource::CMediaSource() { m_pSinksMutex = SDL_CreateMutex(); if (m_pSinksMutex == NULL) { debug_message("CreateMutex error"); } for (int i = 0; i < MAX_SINKS; i++) { m_sinks[i] = NULL; } m_source = false; m_sourceVideo = false; m_sourceAudio = false; m_maxAheadDuration = TimestampTicks / 20 ; // 50 msec m_videoSource = this; m_videoSrcYImage = NULL; m_videoDstYImage = NULL; m_videoYResizer = NULL; m_videoSrcUVImage = NULL; m_videoDstUVImage = NULL; m_videoUVResizer = NULL; m_videoEncoder = NULL; m_videoDstPrevImage = NULL; m_videoDstPrevReconstructImage = NULL; m_videoDstPrevFrame = NULL; m_audioPreEncodingBuffer = NULL; m_audioEncoder = NULL; m_audioResample = NULL;}CMediaSource::~CMediaSource() { SDL_DestroyMutex(m_pSinksMutex); m_pSinksMutex = NULL; if (m_audioResample != NULL) { for (int ix = 0; ix < m_audioDstChannels; ix++) { free(m_audioResample[ix]); m_audioResample[ix] = NULL; } free(m_audioResample); m_audioResample = NULL; }}bool CMediaSource::AddSink(CMediaSink* pSink) { bool rc = false; if (SDL_LockMutex(m_pSinksMutex) == -1) { debug_message("AddSink LockMutex error"); return rc; } for (int i = 0; i < MAX_SINKS; i++) { if (m_sinks[i] == NULL) { m_sinks[i] = pSink; rc = true; break; } } if (SDL_UnlockMutex(m_pSinksMutex) == -1) { debug_message("UnlockMutex error"); } return rc;}void CMediaSource::RemoveSink(CMediaSink* pSink) { if (SDL_LockMutex(m_pSinksMutex) == -1) { debug_message("RemoveSink LockMutex error"); return; } for (int i = 0; i < MAX_SINKS; i++) { if (m_sinks[i] == pSink) { int j; for (j = i; j < MAX_SINKS - 1; j++) { m_sinks[j] = m_sinks[j+1]; } m_sinks[j] = NULL; break; } } if (SDL_UnlockMutex(m_pSinksMutex) == -1) { debug_message("UnlockMutex error"); }}void CMediaSource::RemoveAllSinks(void) { if (SDL_LockMutex(m_pSinksMutex) == -1) { debug_message("RemoveAllSinks LockMutex error"); return; } for (int i = 0; i < MAX_SINKS; i++) { if (m_sinks[i] == NULL) { break; } m_sinks[i] = NULL; } if (SDL_UnlockMutex(m_pSinksMutex) == -1) { debug_message("UnlockMutex error"); }}Duration CMediaSource::GetElapsedDuration(){ if (m_sourceVideo && m_sourceAudio) { return MIN(m_videoSrcElapsedDuration, m_audioSrcElapsedDuration); } else if (m_sourceVideo) { return m_videoSrcElapsedDuration; } else if (m_sourceAudio) { return m_audioSrcElapsedDuration; } return 0;}void CMediaSource::ForwardFrame(CMediaFrame* pFrame){ if (SDL_LockMutex(m_pSinksMutex) == -1) { debug_message("ForwardFrame LockMutex error"); return; } for (int i = 0; i < MAX_SINKS; i++) { if (m_sinks[i] == NULL) { break; } m_sinks[i]->EnqueueFrame(pFrame); } if (SDL_UnlockMutex(m_pSinksMutex) == -1) { debug_message("UnlockMutex error"); } if (pFrame->RemoveReference()) delete pFrame; return;}void CMediaSource::DoStopSource(){ if (!m_source) { return; } DoStopVideo(); DoStopAudio(); m_source = false;}bool CMediaSource::InitVideo( MediaType srcType, bool realTime){ m_sourceRealTime = realTime; m_sinkRealTime = m_pConfig->GetBoolValue(CONFIG_RTP_ENABLE); m_videoSrcType = srcType; m_videoSrcFrameNumber = 0; m_audioSrcFrameNumber = 0; // ensure audio is also at zero m_videoDstFrameRate = m_pConfig->GetFloatValue(CONFIG_VIDEO_FRAME_RATE); m_videoDstFrameDuration = (Duration)(((float)TimestampTicks / m_videoDstFrameRate) + 0.5); m_videoDstFrameNumber = 0; m_videoEncodedFrames = 0; m_videoDstWidth = m_pConfig->m_videoWidth; m_videoDstHeight = m_pConfig->m_videoHeight; m_videoDstAspectRatio = (float)m_pConfig->m_videoWidth / (float)m_pConfig->m_videoHeight; m_videoDstYSize = m_videoDstWidth * m_videoDstHeight; m_videoDstUVSize = m_videoDstYSize / 4; m_videoDstYUVSize = (m_videoDstYSize * 3) / 2; // intialize encoder m_videoEncoder = VideoEncoderCreate(m_pConfig->GetStringValue(CONFIG_VIDEO_ENCODER)); m_videoDstType = m_videoEncoder->GetFrameType(); m_videoDstType = MPEG4VIDEOFRAME; if (!m_videoEncoder) { return false; } if (!m_videoEncoder->Init(m_pConfig, realTime)) { delete m_videoEncoder; m_videoEncoder = NULL; return false; }#ifdef DEBUG_VCODEC_SHADOW m_videoEncoderShadow = VideoEncoderCreate("ffmpeg"); m_videoEncoderShadow->Init(m_pConfig, realTime);#endif m_videoWantKeyFrame = true; m_videoEncodingDrift = 0; m_videoEncodingMaxDrift = m_videoDstFrameDuration; m_videoSrcElapsedDuration = 0; m_videoDstElapsedDuration = 0; m_otherTotalDrift = 0; m_otherLastTotalDrift = 0; m_videoDstPrevImage = NULL; m_videoDstPrevReconstructImage = NULL; m_videoDstPrevFrame = NULL; m_videoDstPrevFrameLength = 0; return true;}void CMediaSource::SetVideoSrcSize( u_int16_t srcWidth, u_int16_t srcHeight, u_int16_t srcStride, bool matchAspectRatios){ // N.B. InitVideo() must be called first m_videoSrcWidth = srcWidth; m_videoSrcHeight = srcHeight; m_videoSrcAspectRatio = (float)srcWidth / (float)srcHeight; m_videoMatchAspectRatios = matchAspectRatios; SetVideoSrcStride(srcStride);}void CMediaSource::SetVideoSrcStride( u_int16_t srcStride){ // N.B. SetVideoSrcSize() should be called once before m_videoSrcYStride = srcStride; m_videoSrcUVStride = srcStride / 2; // these next three may change below m_videoSrcAdjustedHeight = m_videoSrcHeight; m_videoSrcYCrop = 0; m_videoSrcUVCrop = 0; // match aspect ratios if (m_videoMatchAspectRatios && fabs(m_videoSrcAspectRatio - m_videoDstAspectRatio) > 0.01) { m_videoSrcAdjustedHeight = (u_int16_t)(m_videoSrcWidth / m_videoDstAspectRatio); if ((m_videoSrcAdjustedHeight % 16) != 0) { m_videoSrcAdjustedHeight += 16 - (m_videoSrcAdjustedHeight % 16); } if (m_videoSrcAspectRatio < m_videoDstAspectRatio) { // crop src m_videoSrcYCrop = m_videoSrcYStride * ((m_videoSrcHeight - m_videoSrcAdjustedHeight) / 2); m_videoSrcUVCrop = m_videoSrcYCrop / 4; } } m_videoSrcYSize = m_videoSrcYStride * MAX(m_videoSrcHeight, m_videoSrcAdjustedHeight); m_videoSrcUVSize = m_videoSrcYSize / 4; m_videoSrcYUVSize = (m_videoSrcYSize * 3) / 2; // resizing DestroyVideoResizer(); if (m_videoSrcWidth != m_videoDstWidth || m_videoSrcAdjustedHeight != m_videoDstHeight) { m_videoSrcYImage = scale_new_image(m_videoSrcWidth, m_videoSrcAdjustedHeight, 1); m_videoSrcYImage->span = m_videoSrcYStride; m_videoDstYImage = scale_new_image(m_videoDstWidth, m_videoDstHeight, 1); m_videoYResizer = scale_image_init(m_videoDstYImage, m_videoSrcYImage, Bell_filter, Bell_support); m_videoSrcUVImage = scale_new_image(m_videoSrcWidth / 2, m_videoSrcAdjustedHeight / 2, 1); m_videoSrcUVImage->span = m_videoSrcUVStride; m_videoDstUVImage = scale_new_image(m_videoDstWidth / 2, m_videoDstHeight / 2, 1); m_videoUVResizer = scale_image_init(m_videoDstUVImage, m_videoSrcUVImage, Bell_filter, Bell_support); }}void CMediaSource::ProcessVideoYUVFrame( u_int8_t* pY, u_int8_t* pU, u_int8_t* pV, u_int16_t yStride, u_int16_t uvStride, Timestamp srcFrameTimestamp){ Duration temp; m_videoSrcPrevElapsedDuration = m_videoSrcElapsedDuration; if (m_videoSrcFrameNumber == 0) { if (m_audioSrcFrameNumber == 0) { m_encodingStartTimestamp = GetTimestamp(); } m_videoStartTimestamp = srcFrameTimestamp; } m_videoSrcFrameNumber++; temp = srcFrameTimestamp - m_videoStartTimestamp; if (temp <= m_videoSrcElapsedDuration) {#ifdef DEBUG_SYNC error_message("video duplication in source timestamp %llu %llu", srcFrameTimestamp, temp);#endif } m_videoSrcElapsedDuration = temp; // drop src frames as needed to match target frame rate if (m_videoDstElapsedDuration > m_videoSrcElapsedDuration) {#ifdef DEBUG_SYNC debug_message("Dropping at %llu before %llu", m_videoSrcElapsedDuration, m_videoDstElapsedDuration);#endif return; } // if we're running in real-time mode if (m_sourceRealTime) { // add any external drift (i.e. audio encoding drift) // to our drift measurement#if 0 debug_message("drift %llu other last %llu %llu", m_videoEncodingDrift, m_otherLastTotalDrift, m_otherTotalDrift);#endif m_videoEncodingDrift += m_otherTotalDrift - m_otherLastTotalDrift; m_otherLastTotalDrift = m_otherTotalDrift; // check if we are falling behind if (m_videoEncodingDrift >= m_videoEncodingMaxDrift) {#ifdef DEBUG_SYNC_DROPS debug_message("video skipping src frame %llu drift %llu max %llu", m_videoSrcElapsedDuration, m_videoEncodingDrift, m_videoEncodingMaxDrift); if (m_otherLastTotalDrift != 0 || m_otherTotalDrift != 0) { debug_message("video other last %llu %llu", m_otherLastTotalDrift, m_otherTotalDrift); }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -