如何使用ffmpeg实现h264流传输+H264实现RTP传输数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用ffmpeg实现h264流传输+H264实现RTP传输数据相关的知识,希望对你有一定的参考价值。

参考技术A H264编码后,就可以逐个NAL做RTP打包,接收端RTP解包,然后H264解码,渲染了。
FFMPEG应该可以实现。本回答被提问者采纳

ffmpeg 探测流

// Decoder.cpp : Defines the exported functions for the DLL application.

//


#include "stdafx.h"

#include "Decoder.h"

#include "DeException.h"

#include <direct.h>

#include <string>

#include <io.h>

#include "Demuxer.h"

//////////////////////////////////////////////////////////////////////////

///decoder class

/////////////////////////////


enum {

FLV_TAG_TYPE_AUDIO = 0x08,

FLV_TAG_TYPE_VIDEO = 0x09,

FLV_TAG_TYPE_META = 0x12,

};


CDecoder::CDecoder()

: IDecoderStream()

, m_TimeStampe(nullptr)

, m_pContext(nullptr)

, m_eStatus(eUndefine)

, m_bAudio(false)

, m_nStep(0)

, av_sync_type(0)

, seek_req(0)

, seek_flags(0)

, seek_pos(0)

, m_ePlayType(eFile)

, m_pAvioBuf(nullptr)

{

m_fPlaySpeed = 1.0;

m_pDemuxer = nullptr;

m_szPlayFile[0] = ‘\0‘;

ZeroMemory(&m_FlushPkt, sizeof(AVPacket));

av_init_packet(&m_FlushPkt);

m_FlushPkt.data = (unsigned char *) "FLUSH";


m_strCaptureFile = "";

m_strPictureFolder = "";

m_strRecodFolder = "";

m_strModelPath = "";


//get model path.

char buffer[512] = {0};

_getcwd(buffer, 512);

m_strModelPath = buffer;


m_pVideoc = new VideoDecodec(this);

m_pAudioc  = new AudioDecodec(this);

}


CDecoder::~CDecoder()

{

delete m_pVideoc;

delete m_pAudioc;

if (m_pDemuxer)

{

delete m_pDemuxer;

}

}


double CDecoder::GetExternalClock()

{

    return av_gettime() / 1000000.0;

}


double CDecoder::GetVideoClock()

{

double delta = 0;

double pts = 0;


if (m_bPaused)

{

pts = m_pVideoc->GetCurPts();

}

else

{

delta = (av_gettime() - m_pVideoc->video_current_pts_time) / 1000000.0;

pts = m_pVideoc->GetCurPts() + delta;

}


return pts;

}


double CDecoder::GetAudioClock()

{

double pts = 0;


if (m_bPaused)

{

pts = m_pAudioc->GetCurPts();

}

if (m_pAudioc->audioStream >= 0)

{

pts = m_pAudioc->GetAudioClock();

}


return pts;

}


double CDecoder::GetMasterClock() 

{

double pts = 0;


if (av_sync_type == AV_SYNC_VIDEO_MASTER)

{

pts = GetVideoClock();

else if (av_sync_type == AV_SYNC_AUDIO_MASTER)

{

pts = GetAudioClock();

else 

{

pts = GetExternalClock();

}


return pts;

}


/* pause or resume the video */

void CDecoder::StreamTogglePause()

{

if (m_bPaused)

{

m_pVideoc->frame_timer += av_gettime() / 1000000.0 + - m_pVideoc->GetCurPts();

// if (is->read_pause_return != AVERROR(ENOSYS))

// {

// m_pVideoc->video_current_pts = m_pVideoc->video_current_pts_drift + av_gettime() / 1000000.0;

// }


// m_pVideoc->video_current_pts_drift = m_pVideoc->video_current_pts - av_gettime() / 1000000.0;

}

m_bPaused = !m_bPaused;

}


Uint32 CDecoder::SdlRefreshTimerCb(Uint32 interval, void *opaque)

{

    SDL_Event event;

    event.type = FF_REFRESH_EVENT;

event.user.data1 = opaque;

    SDL_PushEvent(&event);

    return 0;

}


void CDecoder::ScheduleRefresh(int nDelay)

{

SDL_AddTimer(nDelay, SdlRefreshTimerCb, this);

}


bool CDecoder::DirectShow()

{

return (eFile != m_ePlayType);

}


int CDecoder::DecodeInterruptCb(void *opaque) 

{

    //return (global_video_state && global_video_state->quit);

return 0;

}


int CDecoder::DecodeFileThread(void *arg)

{

CDecoder *pDecoder = (CDecoder *) arg;

AVFormatContext *pFormatCtx = pDecoder->m_pVideoc->ic;

AVPacket  pkt1 = {0};

AVPacket* packet = &pkt1;

unsigned int i = 0;


VideoDecodec* pVideo  = pDecoder->m_pVideoc;

AudioDecodec* pAudioc = pDecoder->m_pAudioc;


try

{

//main decode loop

/* 读包的主循环, av_read_frame不停的从文件中读取数据包*/

while(!pDecoder->IsStop())

{

if (pDecoder->seek_req) 

{

int stream_index = -1;

int64_t seek_target = pDecoder->seek_pos * 100;


if (pVideo->videoStream >= 0)

stream_index = pVideo->videoStream;

else if (pAudioc->audioStream >= 0)

stream_index = pAudioc->audioStream;


if (stream_index >= 0)

{

AVRational bq = {1, 100};

seek_target = av_rescale_q(seek_target, bq, pFormatCtx->streams[stream_index]->time_base);

}


if (av_seek_frame(pVideo->ic, stream_index, seek_target, pDecoder->seek_flags) < 0) 

{

_TCHAR szData[256]  = {0};

wsprintf(szData, _T("Can not find pos: %d"), seek_target/AV_TIME_BASE);

OutputDebugString(szData);

}

else 

{

if (pAudioc && pAudioc->audioStream >= 0)

{

pAudioc->audioq.PacketQueueFlush();

pAudioc->audioq.PacketQueuePut(&pDecoder->m_FlushPkt);//内存泄露???

}


if (pVideo->videoStream >= 0)

{

pVideo->videoq.PacketQueueFlush();

pVideo->videoq.PacketQueuePut(&pDecoder->m_FlushPkt);//内存泄露???

}

}


pDecoder->seek_req = 0;

}


//seek  stuff goes here

/* 这里audioq.size是指队列中的所有数据包带的音频数据的总量或者视频数据总量,并不是包的数量 */

if (pAudioc->audioq.size > MAX_AUDIOQ_SIZE || pVideo->videoq.size > MAX_VIDEOQ_SIZE)

{

SDL_Delay(10);

continue;

}


if (av_read_frame(pVideo->ic, packet) < 0)

{

if (pVideo->ic->pb->error == 0)

{

pDecoder->m_eStatus = eStop;

DeException exMsg(ePlayEnd, pDecoder);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, pDecoder, ePlayEnd, exMsg.GetCurString());

exMsg.Execute();

break;

//continue;/* no error; wait for user input, should be stop in the file mode */

}

else

{

break;

}

}


//record data.

if (pDecoder->m_pDemuxer)

{

pDecoder->m_pDemuxer->Demuxer(pFormatCtx->streams[packet->stream_index], *packet);

}


if (pDecoder->IsStop())

break;


// Is this a packet from the video stream?

if (packet->stream_index == pVideo->videoStream)

{

pVideo->videoq.PacketQueuePut(packet);//内存泄露???

else if (packet->stream_index == pAudioc->audioStream) 

{

pAudioc->audioq.PacketQueuePut(packet);//内存泄露???

else 

{

av_packet_unref(packet);

}

}

}

catch(DeException ex)

{

pDecoder->parse_tid = 0;

return 1;

}


pDecoder->parse_tid = 0;

//av_packet_unref(packet);


    return 0;



int CDecoder::ReadStreamData(void *pContext, uint8_t *buf, int buf_size) 

{

if (pContext)

{

PRAME frame = {0};

frame.pFrame = buf;

frame.FrameLen = buf_size;

int nLen = 0;


CDecoder* pDecoder = (CDecoder*)pContext;

nLen = pDecoder->GetOneCompletesFrame(&frame);


return nLen;

}


return 0;

}


int CDecoder::FindStreamIndex(AVFormatContext *pformat_ctx, int& video_stream, int& audio_stream)

{

int i = 0;

video_stream = -1;

audio_stream = -1;


for (i = 0; i < pformat_ctx->nb_streams; i++)

{

if (pformat_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)

{

video_stream = i;

}


if (pformat_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)

{

audio_stream = i;

}

}


return 0;

}


int CDecoder::DecodeStreamThread(void *arg) 

{

CDecoder* pDecoder = (CDecoder *) arg;

VideoDecodec* pVideo = pDecoder->m_pVideoc;

AudioDecodec* pAudioc = pDecoder->m_pAudioc;


AVFormatContext *pFormatCtx = pVideo->ic;

AVPacket pkt1, *packet = &pkt1;

unsigned int i = 0;


try

{

//main decode loop

/* 读包的主循环, av_read_frame不停的从文件中读取数据包*/

while(!pDecoder->IsStop())

{

if(pDecoder->m_bPaused)// 2 stop

{

SDL_Delay(2);

continue;

}


//seek  stuff goes here

/* 这里audioq.size是指队列中的所有数据包带的音频数据的总量或者视频数据总量,并不是包的数量 */

if (pAudioc->audioq.size > MAX_AUDIOQ_SIZE || pVideo->videoq.size > MAX_VIDEOQ_SIZE)

{

SDL_Delay(10);

continue;

}


if (av_read_frame(pVideo->ic, packet) < 0) 

{

if (pVideo->ic->pb->error == 0)

{

SDL_Delay(10); /* no error; wait for user input */

continue;

}

else

{

break;

}

}


//record data.

if (pDecoder->m_pDemuxer)

{

pDecoder->m_pDemuxer->Demuxer(pFormatCtx->streams[packet->stream_index], *packet);

}


// Is this a packet from the video stream?

if (packet->stream_index == pVideo->videoStream)

{

pVideo->videoq.PacketQueuePut(packet);//内存泄露???

else if (packet->stream_index == pAudioc->audioStream)

{

if (pAudioc->IsPlay())

{

pAudioc->audioq.PacketQueuePut(packet);//内存泄露???

}

}

else 

{

av_packet_unref(packet);

}

}


//av_free(packet);


/*all done - wait for it*/

// while (true)

// {

// SDL_Delay(100);

// }


//av_free(buf);

}

catch(DeException ex)

{

pDecoder->parse_tid = 0;

return 1;

}


pDecoder->parse_tid = 0;


return 0;

}


void CDecoder::UpdatePteCall()

{

if (m_TimeStampe != nullptr && m_pVideoc->video_st)

{

stTimeStampe time = {0};

//this may not correct.

time.dCurrentTime = GetCutPts();

//time.dCurrentTime =  packet->dts * av_q2d(pVideo->video_st->time_base);

time.dTotalTime  =  m_pVideoc->ic->duration * av_q2d(m_pVideoc->video_st->time_base);

m_TimeStampe((PLAYHANDLE)this, m_pContext, time);

}

}


double CDecoder::GetCutPts()

{

double pts = 0;

if (av_sync_type == AV_SYNC_VIDEO_MASTER)

{

pts = m_pVideoc->GetCurPts();

else if (av_sync_type == AV_SYNC_AUDIO_MASTER)

{

pts = m_pAudioc->GetCurPts();

}


return pts;

}



int CDecoder::InitialzieDecodeParas(DecoderParas* _Out_ paras)

{

SDL_Event event;

event.type = FF_START_DECODER_EVENT;

event.user.data1 = this;

SDL_PushEvent(&event);


return 0;

}


int CDecoder::GetOneCompletesFrame(PRAME* _Out_ pFrame)

{

return __super::GetOneCompletesFrame(pFrame);

}


//for download, playback.

int CDecoder::NoDataRcvEvent(char* pFileName)

{

//TODO: how about playback.

if (m_ePlayType == eDownload)

{

DeException exMsg(eDw this, false);

MODIFY_MSG(exMsg.m_szTemp, exMsg.GetCurString(), pFileName);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eDw exMsg.m_szTemp);

exMsg.Execute();

}


SDL_Event event;

event.type = FF_STOP_RTSP_REV;

event.user.data1 = this;

SDL_PushEvent(&event);


return 0;

}


int CDecoder::OnNotDataRcv()

{

DeException exMsg(eOnNoDataRev, this, false);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eOnNoDataRev, exMsg.GetCurString());

exMsg.Execute();


return 0;

}


void CDecoder::StopRtsp()

{

if (m_pRtsp)

{

m_pRtsp->StopPlay();

delete m_pRtsp;

m_pRtsp = nullptr;

}


DeException exMsg(eNoDataReceive, this, false);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eNoDataReceive, exMsg.GetCurString());

exMsg.Execute();


SDL_Event event;

event.type = FF_QUIT_EVENT;

event.user.data1 = this;

SDL_PushEvent(&event);

}


int CDecoder::RecordInfo(stFileInfo fileInfo)

{

DeException exMsg(eRecordSize, this, false);

MODIFY_MSG(exMsg.m_szTemp, exMsg.GetCurString(), fileInfo.ulFileSize);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eRecordSize, exMsg.m_szTemp);

exMsg.Execute();


return 0;

}


///////////////////////public interface///////////////////////////////////

/////////////////////////export interface.//////////////////////////////


int CDecoder::StartPlay(const stPlay &play)

{

m_pAudioc->Initialize();

m_pVideoc->Initialize();

m_ePlayType = play.type;


switch (play.type)

{

case eFile:

return StartFilePlay(play);

break;

case eRealPlay:

case ePlayback:

return StartStreamPlay(play);

break;

case eDownload:

return StartDownload(play);

break;

default:

break;

}


return 0;

}


int CDecoder::StartFilePlay(const stPlay &play)

{

AVIOInterruptCB interupt_cb = {0};


try

{

if (play.url[0] == ‘\0‘ || _access(play.url, 0))

{

DeException exMsg(eFileNoExist, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eFileNoExist, exMsg.GetCurString());

exMsg.Execute();

}


if (!IsWindow(play.wndPlay))

{

DeException exMsg(eWndInvalid, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eWndInvalid, exMsg.GetCurString());

exMsg.Execute();

}


strcpy_s(m_szPlayFile, sizeof(m_szPlayFile), play.url);

m_pVideoc->pictq->wndPlay  = play.wndPlay;

m_bAudio   = play.bAudio;


ScheduleRefresh(10);

av_sync_type = DEFAULT_AV_SYNC_TYPE;

m_pVideoc->videoStream = -1;

m_pAudioc->audioStream = -1;


// will interrupt blocking functions if we quit!

interupt_cb.callback = DecodeInterruptCb;

interupt_cb.opaque   = this;


if (avio_open2(&m_pVideoc->io_ctx, m_szPlayFile, 0, &interupt_cb, NULL)) 

{

DeException exMsg(eOpenIOError, this);

MODIFY_MSG(exMsg.m_szTemp, exMsg.GetCurString(), m_szPlayFile);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eOpenIOError, exMsg.m_szTemp);

exMsg.Execute();

}


//Open video file

if (avformat_open_input(&m_pVideoc->ic, m_szPlayFile, NULL, NULL) != 0)

{

DeException exMsg(eOpenFileError, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eOpenFileError, exMsg.GetCurString());

exMsg.Execute();

}


//Retrieve stream information

if (avformat_find_stream_info(m_pVideoc->ic, NULL) < 0)

{

DeException exMsg(eRetrieveStreamInformation, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eRetrieveStreamInformation, exMsg.GetCurString());

exMsg.Execute();

}


int nRetCtx = -1;

//Dump information about file onto standard error

av_dump_format(m_pVideoc->ic, 0, m_szPlayFile, 0);

//Find the first video stream

FindStreamIndex(m_pVideoc->ic, m_pVideoc->videoStream, m_pAudioc->audioStream);

if (m_pAudioc->audioStream >= 0 && m_bAudio)

{

m_pAudioc->m_codecCtx = avcodec_alloc_context3(NULL);

if (m_pAudioc->m_codecCtx == nullptr)

{

DeException exMsg(eAvcodecAllocContextFailed, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eAvcodecAllocContextFailed, exMsg.GetCurString());

exMsg.Execute();

}


nRetCtx = avcodec_parameters_to_context(m_pAudioc->m_codecCtx, m_pVideoc->ic->streams[m_pAudioc->audioStream]->codecpar);

/* 所有设置SDL音频流信息的步骤都在这个函数里完成 */

int nError = m_pAudioc->AudioStreamComponentOpen(m_pVideoc->ic);

}

else

{

m_pAudioc->audioStream = -1;

}


if (m_pVideoc->videoStream >= 0)

{

m_pVideoc->m_codecCtx = avcodec_alloc_context3(NULL);

if (m_pVideoc->m_codecCtx == nullptr)

{

DeException exMsg(eAvcodecAllocContextFailed, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eAvcodecAllocContextFailed, exMsg.GetCurString());

exMsg.Execute();

}


nRetCtx = avcodec_parameters_to_context(m_pVideoc->m_codecCtx, m_pVideoc->ic->streams[m_pVideoc->videoStream]->codecpar);

m_pVideoc->VideoStreamComponentOpen();

}


//to do if 

if (m_pVideoc->videoStream < 0 && m_pAudioc->audioStream < 0)

{

DeException exMsg(eOpenCodecFailed, this);

MODIFY_MSG(exMsg.m_szTemp, exMsg.GetCurString(), m_szPlayFile);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eOpenCodecFailed, exMsg.m_szTemp);

exMsg.Execute();

}

//内存分配失败??

parse_tid = SDL_CreateThread(DecodeFileThread, "parse_thread", this);

if (!parse_tid)

{

DeException exMsg(cReateDecodeThreadFailed, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, cReateDecodeThreadFailed, exMsg.GetCurString());

exMsg.Execute();

}    

}

catch(DeException ex)

{

return ex.m_nCode;

}


return 0;

}  


int CDecoder::StartStreamPlay(const stPlay &play)

{

m_pVideoc->pictq->wndPlay= play.wndPlay;

m_bAudio = play.bAudio;

m_pVideoc->videoStream = -1;

m_pAudioc->audioStream = -1;


m_pAvioBuf = (uint8_t*)av_mallocz(sizeof(uint8_t)*BUF_SIZE);


AVIOInterruptCB interupt_cb = {0};


// will interrupt blocking functions if we quit!

interupt_cb.callback = nullptr;

interupt_cb.opaque = this;


//Create rtsp stream

StreamPara para = {0};


para.pDecoder = this;

para.eType = (play.type == eRealPlay) ? eRtspRealPlay : eRtspPlayback;

para.eTransType = (play.eTranType == TransmissionType::eUDP) ? RtspTrans::eRtspUDP: RtspTrans::eRtspTCP;


strcpy_s(para.szUrl, 260, play.url);

strcpy_s(para.szIP, 16, "127.0.0.1");

strcpy_s(para.szUser, 64, play.szUser);

strcpy_s(para.szPassword, 64, play.szPassward);

//for playback and download

strcpy_s(para.szFileName, 512, play.szFileName);


try

{

if (!IsWindow(play.wndPlay))

{

DeException exMsg(eWndInvalid, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eWndInvalid, exMsg.GetCurString());

exMsg.Execute();

}


m_pRtsp = new RtspClient();

int nRet = m_pRtsp->StartPlay(para);

if (nRet != 0)

{

m_pRtsp->StopPlay();

delete m_pRtsp;

m_pRtsp = nullptr;


DeException exMsg(eRtspError, this);

MODIFY_MSG(exMsg.m_szTemp, exMsg.GetCurString(), nRet);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eRtspError, exMsg.m_szTemp);

exMsg.Execute();

}

}

catch(...)

{

return eRtspError;

}


return 0;

}


int CDecoder::StartDownload(const stPlay &play)

{

//Create rtsp stream

StreamPara para = {0};

para.pDecoder = this;

para.eType  = RequestType::eRtspDownLoad;

para.eTransType = (play.eTranType == TransmissionType::eUDP) ? RtspTrans::eRtspUDP: RtspTrans::eRtspTCP;


char szFileName[512] = {0};

strcpy_s(para.szUrl, 260, play.url);

strcpy_s(para.szIP, 16, "127.0.0.1");

strcpy_s(para.szUser, 64, play.szUser);

strcpy_s(para.szPassword, 64, play.szPassward);


//for playback and download

char* pFolder = "Download";

_mkdir(pFolder);


//set the file name.

if (nullptr == play.szFileName || ‘\0‘ == play.szFileName[0])

{

time_t m_Time;

struct tm timeinfo = {0};

time ( &m_Time );

localtime_s(&timeinfo, &m_Time);

sprintf_s(szFileName, "%04d%02d%02d_%02d%02d%02d.mpg", timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);

sprintf_s(para.szFileName, 512, "%s\\%s\\%s", m_strModelPath.c_str(), pFolder, szFileName);

}

else

{

sprintf_s(para.szFileName, 512, play.szFileName);

}


try

{

m_pRtsp = new RtspClient();

int nRet = m_pRtsp->StartPlay(para);

if (nRet != 0)

{

m_pRtsp->StopPlay();

delete m_pRtsp;

m_pRtsp = nullptr;


DeException exMsg(eRtspError, this);

MODIFY_MSG(exMsg.m_szTemp, exMsg.GetCurString(), nRet);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eRtspError, exMsg.m_szTemp);

exMsg.Execute();

}

else

{

m_fPlaySpeed = 4; 

SetSpeed(1);

}

}

catch(...)

{

return eRtspError;

}


return 0;

}


void CDecoder::DeCodeStream()

{

AVInputFormat *piFmt = NULL;

AVFormatContext *pFormatCtx = nullptr;


try

{

m_pVideoc->io_ctx = avio_alloc_context(m_pAvioBuf, BUF_SIZE, 0, this, ReadStreamData, NULL, NULL);


if (!m_pVideoc->io_ctx) 

{

DeException exMsg(eIOAllocError, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eIOAllocError, exMsg.GetCurString());

exMsg.Execute();

}


if (av_probe_input_buffer(m_pVideoc->io_ctx, &piFmt, "", NULL, 0, 0) < 0) 

{

av_free(m_pVideoc->io_ctx);

DeException exMsg(eProbeError, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eProbeError, exMsg.GetCurString());

exMsg.Execute();

else 

{

fprintf(stdout, "probe success!\n");

fprintf(stdout, "format: %s[%s]\n", piFmt->name, piFmt->long_name);

}


pFormatCtx = avformat_alloc_context();

pFormatCtx->pb = m_pVideoc->io_ctx;


if (avformat_open_input(&pFormatCtx, "", piFmt, NULL) < 0) 

{

av_free(m_pVideoc->io_ctx);

avformat_free_context(m_pVideoc->ic);


DeException exMsg(eAvformatOpenError, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eAvformatOpenError, exMsg.GetCurString());

exMsg.Execute();

}

else 

{

fprintf(stdout, "open stream success!\n");

}


m_pVideoc->ic = pFormatCtx;

//m_pCodec = 

//TODO:must set the capabilities

//AVCodec *codec;

//AVCodecContext *c;


// if(m_pVideoc->io_ctx->capabilities&CODEC_CAP_TRUNCATED)

// c->flags|= CODEC_FLAG_TRUNCATED; 

//fixed find stream info to  slow.

AVDictionary* pOptions = NULL;

pFormatCtx->probesize = 200 *1024;

pFormatCtx->max_analyze_duration = 3 * AV_TIME_BASE;


//Retrieve stream information

// if (avformat_find_stream_info(pFormatCtx, &pOptions) < 0)

// {

// DeException exMsg(eStreamInforError, this);

// OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eStreamInforError, exMsg.GetCurString());

// exMsg.Execute();

// //return -1; // Couldn‘t find stream information

// }

InitDecode(pFormatCtx);


//Dump information about file onto standard error

av_dump_format(pFormatCtx, 0, "", 0);


int nRetCtx = -1;

//Find the first video stream

FindStreamIndex(pFormatCtx, m_pVideoc->videoStream, m_pAudioc->audioStream);

if (m_pVideoc->videoStream >= 0)

{

m_pVideoc->m_codecCtx = avcodec_alloc_context3(NULL);

if (m_pVideoc->m_codecCtx == nullptr)

{

DeException exMsg(eAvcodecAllocContextFailed, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eAvcodecAllocContextFailed, exMsg.GetCurString());

exMsg.Execute();

}

/* 所有设置SDL音频流信息的步骤都在这个函数里完成 */

nRetCtx = avcodec_parameters_to_context(m_pVideoc->m_codecCtx, pFormatCtx->streams[m_pVideoc->videoStream]->codecpar);

m_pVideoc->VideoStreamComponentOpen();

}


if (m_bAudio && m_pAudioc->audioStream >= 0)

{

m_pAudioc->m_codecCtx = avcodec_alloc_context3(NULL);

if (m_pAudioc->m_codecCtx == nullptr)

{

DeException exMsg(eAvcodecAllocContextFailed, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eAvcodecAllocContextFailed, exMsg.GetCurString());

exMsg.Execute();

}


nRetCtx = avcodec_parameters_to_context(m_pAudioc->m_codecCtx, pFormatCtx->streams[m_pAudioc->audioStream]->codecpar);

m_pAudioc->AudioStreamComponentOpen(pFormatCtx);

}

else

{

m_pAudioc->audioStream = -1;

}


if (m_pVideoc->videoStream < 0 && m_pAudioc->audioStream < 0)

{

DeException exMsg(eOpenCodecFailed, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eOpenCodecFailed, exMsg.GetCurString());

exMsg.Execute();

}


m_szPlayFile[0] = ‘\0‘;

ScheduleRefresh(10);

m_eStatus = ePlay;


av_sync_type = DEFAULT_AV_SYNC_TYPE;

parse_tid = SDL_CreateThread(DecodeStreamThread, "parse_thread", this);


if (!parse_tid) 

{

DeException exMsg(cReateDecodeThreadFailed, this);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, cReateDecodeThreadFailed, exMsg.GetCurString());

exMsg.Execute();

}    

}

catch(DeException ex)

{

//play false

if (m_pRtsp)

m_pRtsp->StopPlay();

ex;

//return ex.m_nCode;

}

}


AVStream* CDecoder::CreateStream(AVFormatContext* pFormatContext, int nCodecType)

{

AVStream *st = avformat_new_stream(pFormatContext, NULL);

if (!st)

return NULL;

st->codecpar->codec_type = (AVMediaType)nCodecType;

return st;

}


int CDecoder::GetVideoExtraData(AVFormatContext* pFormatContext, int nVideoIndex)

{

int  type, size, flags, pos, stream_type;

int ret = -1;

int64_t dts;

bool got_extradata = false;


if (!pFormatContext || nVideoIndex < 0 || nVideoIndex > 2)

return ret;


for (;; avio_skip(pFormatContext->pb, 4)) {

pos = avio_tell(pFormatContext->pb);

type = avio_r8(pFormatContext->pb);

size = avio_rb24(pFormatContext->pb);

dts = avio_rb24(pFormatContext->pb);

dts |= avio_r8(pFormatContext->pb) << 24;

avio_skip(pFormatContext->pb, 3);


if (0 == size)

break;

if (FLV_TAG_TYPE_AUDIO == type || FLV_TAG_TYPE_META == type) {

/*if audio or meta tags, skip them.*/

avio_seek(pFormatContext->pb, size, SEEK_CUR);

}

else if (type == FLV_TAG_TYPE_VIDEO) {

/*if the first video tag, read the sps/pps info from it. then break.*/

size -= 5;

pFormatContext->streams[nVideoIndex]->codecpar->extradata = (uint8_t*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);

if (NULL == pFormatContext->streams[nVideoIndex]->codecpar->extradata)

break;

memset(pFormatContext->streams[nVideoIndex]->codecpar->extradata, 0, size + FF_INPUT_BUFFER_PADDING_SIZE);

memcpy(pFormatContext->streams[nVideoIndex]->codecpar->extradata, pFormatContext->pb->buf_ptr + 5, size);

pFormatContext->streams[nVideoIndex]->codecpar->extradata_size = size;

ret = 0;

got_extradata = true;

}

else {

/*The type unknown,something wrong.*/

break;

}


if (got_extradata)

break;

}


return ret;

}


int CDecoder::InitDecode(AVFormatContext *pFormatContext)

{

int video_index = -1;

int audio_index = -1;

int ret = -1;


if (!pFormatContext)

return ret;


/*

Get video stream index, if no video stream then create it.

And audio so on.

*/

if (0 == pFormatContext->nb_streams) {

CreateStream(pFormatContext, AVMEDIA_TYPE_VIDEO);

CreateStream(pFormatContext, AVMEDIA_TYPE_AUDIO);

video_index = 0;

audio_index = 1;

}

else if (1 == pFormatContext->nb_streams) {

if (AVMEDIA_TYPE_VIDEO == pFormatContext->streams[0]->codecpar->codec_type) {

CreateStream(pFormatContext, AVMEDIA_TYPE_AUDIO);

video_index = 0;

audio_index = 1;

}

else if (AVMEDIA_TYPE_AUDIO == pFormatContext->streams[0]->codecpar->codec_type) {

CreateStream(pFormatContext, AVMEDIA_TYPE_VIDEO);

video_index = 1;

audio_index = 0;

}

}

else if (2 == pFormatContext->nb_streams) {

if (AVMEDIA_TYPE_VIDEO == pFormatContext->streams[0]->codecpar->codec_type) {

video_index = 0;

audio_index = 1;

}

else if (AVMEDIA_TYPE_VIDEO == pFormatContext->streams[1]->codecpar->codec_type) {

video_index = 1;

audio_index = 0;

}

}


/*Error. I can‘t find video stream.*/

if (video_index != 0 && video_index != 1)

return ret;


//Init the audio codec(AAC).

pFormatContext->streams[audio_index]->codecpar->codec_id = AV_CODEC_ID_AAC;

pFormatContext->streams[audio_index]->codecpar->sample_rate = 44100;

// pFormatContext->streams[audio_index]->codec->time_base.den = 44100;

// pFormatContext->streams[audio_index]->codec->time_base.num = 1;

pFormatContext->streams[audio_index]->codecpar->bits_per_coded_sample = 16;

pFormatContext->streams[audio_index]->codecpar->channels = 2;

pFormatContext->streams[audio_index]->codecpar->channel_layout = 3;

pFormatContext->streams[audio_index]->pts_wrap_bits = 32;

pFormatContext->streams[audio_index]->time_base.den = 1000;

pFormatContext->streams[audio_index]->time_base.num = 1;


//Init the video codec(H264).

pFormatContext->streams[video_index]->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;

pFormatContext->streams[video_index]->codecpar->codec_id = AV_CODEC_ID_H264;

pFormatContext->streams[video_index]->codecpar->format = 12;

pFormatContext->streams[video_index]->codecpar->bits_per_raw_sample = 8;

pFormatContext->streams[video_index]->codecpar->profile = 66;

pFormatContext->streams[video_index]->codecpar->level = 42;

pFormatContext->streams[video_index]->codecpar->width = 1920;

pFormatContext->streams[video_index]->codecpar->height = 1080;

pFormatContext->streams[video_index]->codecpar->sample_aspect_ratio.num = 0;

pFormatContext->streams[video_index]->codecpar->sample_aspect_ratio.den = 1;


// pFormatContext->streams[video_index]->codecpar->ticks_per_frame = 2;

// pFormatContext->streams[video_index]->codecpar->pix_fmt = 0;

pFormatContext->streams[video_index]->pts_wrap_bits = 64;

pFormatContext->streams[video_index]->time_base.den = 1200000;

pFormatContext->streams[video_index]->time_base.num = 1;

pFormatContext->streams[video_index]->avg_frame_rate.den = 1;

pFormatContext->streams[video_index]->avg_frame_rate.num = 25;

/*Need to change, different condition has different frame_rate. ‘r_frame_rate‘ is new in ffmepg2.3.3*/

pFormatContext->streams[video_index]->r_frame_rate.den = 25;

pFormatContext->streams[video_index]->r_frame_rate.num = 1;

/* H264 need sps/pps for decoding, so read it from the first video tag.*/

ret = GetVideoExtraData(pFormatContext, video_index);


/*Update the AVFormatContext Info*/

pFormatContext->nb_streams = 1;

/*empty the buffer.*/

pFormatContext->pb->buf_ptr = pFormatContext->pb->buf_end;

/*

something wrong.

TODO: find out the ‘pos‘ means what.

then set it.

*/

// pFormatContext->pb->pos = (int64_t)pFormatContext->pb->buf_end;

// pFormatContext->pb->pos = pFormatContext->pb->buffer_size;

return ret;

}


void CDecoder::VideoRefreshTimer()

{

m_pVideoc->VideoRefreshTimer();

}


void CDecoder::AllocPicture()

{

m_pVideoc->AllocPicture();

}


void CDecoder::FlushData()

{

if (m_pVideoc)

m_pVideoc->FlushData();


if (m_pAudioc)

m_pAudioc->FlushData();

}


void CDecoder::ClearBuffer()

{

int nRet = 0;

if (0 != parse_tid)//stream is end before this.

SDL_WaitThread(parse_tid, &nRet);


m_bStop  = true;

ShowWindow(m_pVideoc->pictq->wndPlay, SW_HIDE);

// av_free(m_pAvioBuf);


m_pAudioc->CleanupBuffer();

m_pVideoc->CleanupBuffer();

av_packet_unref(&m_FlushPkt);


if (m_pRtsp)

{

delete m_pRtsp;

m_pRtsp = nullptr;

}


ShowWindow(m_pVideoc->pictq->wndPlay, SW_SHOW);

}


int CDecoder::StopPlay()

{

//TODO:此处用等待线程的方式退出更为安全。Waitforobject.

if (m_pRtsp)

m_pRtsp->StopPlay();


m_pVideoc->FlushData();

m_eStatus = eStop;

m_bStop  = true;


m_pVideoc->SetSignal();//sometimes can not stop play.


if (m_bAudio)

{

m_pAudioc->FlushData();

m_pAudioc->SetSignal();

}


return 0;

}


void CDecoder::SetTimeStampeCallBack(fTimeStampe pFunction, LPVOID pContext)

{

m_TimeStampe  = pFunction;

m_pContext  = pContext;

}


bool CDecoder::IsStop()

{

return (m_eStatus == eStop);

}


double CDecoder::GetTotalTime()

{

if ( m_ePlayType == eFile)

{

while (m_pVideoc->ic == nullptr)

SDL_Delay(10);


AVStream*  pStream = m_pVideoc->ic->streams[0];

return pStream->duration * av_q2d(pStream->time_base);

}

return 0;

}


PlayStatus CDecoder::GetPlayStatus()

{

return m_eStatus;

}


int CDecoder::PlayConctrol(PlayStatus status)

{

m_eStatus = status;


try

{

switch (status)

{

case ePlay:

{

if (m_pAudioc)

{

m_pAudioc->PauseAudio(0);

}


if (m_pRtsp && (eRealPlay == m_ePlayType || ePlayback == m_ePlayType))

{

stPlayContrl ctrl;

ctrl.eControlType = eRtspContrlPlay;

ZeroMemory(ctrl.szStartTime, sizeof(ctrl.szStartTime));


m_pRtsp->PlayControl(ctrl);

}


m_bPaused = false;

}


break;

case ePause:

{

if (m_pAudioc)

{

m_pAudioc->PauseAudio(1);

m_nStep = 0;//for play by step, now did not implement.

}

//

if (m_pRtsp && (eRealPlay == m_ePlayType || ePlayback == m_ePlayType))

{

stPlayContrl ctrl;

ctrl.eControlType = eRtspContrlPause;

ZeroMemory(ctrl.szStartTime, sizeof(ctrl.szStartTime));


m_pRtsp->PlayControl(ctrl);

}


m_bPaused = true;

}

break;

case eFastForward:

switch (m_ePlayType)

{

case eFile:

StreamSeek(60);

break;

case eRealPlay:

break;

case ePlayback:

SetSpeed(1);

break;

case eDownload:

break;

default:

break;

}

break;

case eFastBackward:

switch (m_ePlayType)

{

case eFile:

StreamSeek(-60, -1);

break;

case eRealPlay:

break;

case ePlayback:

SetSpeed(-1);

break;

case eDownload:

break;

default:

break;

}

break;

case eStep:

{

m_bPaused ? StreamTogglePause() : 0;

m_nStep = 1;

}

case eRecord:

{

if (m_pDemuxer != nullptr)

{

delete m_pDemuxer;

m_pDemuxer = nullptr;

SDL_Delay(10);

}


std::string strFullPath;


if (m_strRecodFolder.empty())

{

time_t m_Time;

char szFileName[512]= {0};

struct tm timeinfo = {0};

time ( &m_Time );

_mkdir("Record");

localtime_s(&timeinfo, &m_Time);

sprintf_s(szFileName, "Record/%04d%02d%02d_%02d%02d%02d.mpg", timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);

strFullPath = m_strModelPath;

strFullPath += "\\";

strFullPath += szFileName;

}

else

{

strFullPath = m_strRecodFolder;

}

FILE* pfRecord = nullptr;

std::string strResult;


if(fopen_s(&pfRecord, strFullPath.c_str(), "wb+") == 0)

{

m_pDemuxer = new CDemuxer();

m_pDemuxer->InitData(pfRecord);

strResult = strFullPath;

}

else

{

strResult = "open file error,";

}

DeException exMsg(eRecordFilePath, this, false);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eRecordFilePath, strResult.c_str());

exMsg.Execute();

}


break;

case eStopRecord:

{

if (m_pDemuxer)

{

delete m_pDemuxer;

m_pDemuxer = nullptr;

SDL_Delay(10);

}

}

break;

case eStop:

StopPlay();

break;

case ePlayAudio:

if (m_pAudioc)

{

m_pAudioc->SetPlayAudio(true);

}

break;

case eStopAudio:

if (m_pAudioc)

{

m_pAudioc->SetPlayAudio(false);

}

break;

default:

break;

}

}

catch (...)

{

return 1;

}


return 0;

}


int CDecoder::SetSoundVolume(int nVolume)

{

if (nullptr == m_pAudioc)

{

return -1;

}

else

{

return m_pAudioc->SetSoundVolume(nVolume);

}


return -1;

}


void CDecoder::SetSpeed(short uSpeed)

{

if (m_pRtsp)

{

stPlayContrl ctrl;

ctrl.eControlType = eRtspContrlScale;

ZeroMemory(ctrl.szStartTime, sizeof(ctrl.szStartTime));


if (uSpeed == -1)

{

if (m_fPlaySpeed > 0.125)

{

ctrl.fScale = m_fPlaySpeed * 0.5;

m_pRtsp->PlayControl(ctrl);

}

}

else if(uSpeed == 1)

{

if (m_fPlaySpeed < 8)

{

ctrl.fScale = m_fPlaySpeed * 2;

m_pRtsp->PlayControl(ctrl);

}

}

}

}


int CDecoder::PlaybackControl(stPlayback ctrl)

{

if (m_pRtsp)

{

stPlayContrl PlaybackContrl;

PlaybackContrl.eControlType = (EnumControl)ctrl.eControlType;

PlaybackContrl.fScale = ctrl.fScale;

strcpy_s(PlaybackContrl.szStartTime, 16, ctrl.szStartTime);


return m_pRtsp->PlayControl(PlaybackContrl);

}


return 0;

}


int CDecoder::CapturePicture(const char* pFileName)

{

m_strCaptureFile = pFileName;

std::string strTickCount;


if (-1 == m_strCaptureFile.find(":") && !m_strPictureFolder.empty())

{

if (pFileName == nullptr || pFileName[0] == ‘\0‘)

{

m_strCaptureFile  = m_strPictureFolder;

m_strCaptureFile += "\\";

m_strCaptureFile += std::to_string(GetTickCount());

m_strCaptureFile += ".jpg";

}

else

{

m_strCaptureFile  = m_strPictureFolder;

m_strCaptureFile  +=  "\\";

m_strCaptureFile  += pFileName;

}

}


if (m_strCaptureFile.empty())

{

//create folder and file.---default file name.

char* pFolder = "CapturePicture";

_mkdir(pFolder);

m_strCaptureFile += m_strModelPath;

m_strCaptureFile += "\\";

m_strCaptureFile += pFolder;

m_strCaptureFile += "\\";

m_strCaptureFile += std::to_string(GetTickCount());

m_strCaptureFile += ".jpg";

}


DeException exMsg(eCapturePicturePath, this, false);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eCapturePicturePath, m_strCaptureFile.c_str());

exMsg.Execute();


return 0;

}


int CDecoder::LocalRecord(const char* pFileName)

{

std::string strFileName = pFileName;


if (-1 == strFileName.find(":") && !m_strRecodFolder.empty())

{

if (pFileName == nullptr || pFileName[0] == ‘\0‘)

{

time_t m_Time;

char szFileName[512]= {0};

struct tm timeinfo = {0};

time ( &m_Time );

localtime_s(&timeinfo, &m_Time);

sprintf_s(szFileName, "%04d%02d%02d_%02d%02d%02d.mpg", timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);

strFileName  = m_strRecodFolder;

strFileName += "\\";

strFileName += szFileName;

}

else

{

strFileName  = m_strRecodFolder;

strFileName  += "\\";

strFileName  += pFileName;

}

}


if (m_pDemuxer != nullptr)

{

delete m_pDemuxer;

m_pDemuxer = nullptr;

SDL_Delay(10);

}


if (strFileName.empty())

{

//create folder and file.---default file name.

char* pFolder = "Record";

_mkdir(pFolder);


time_t m_Time;

char szFileName[512]= {0};

struct tm timeinfo = {0};

time ( &m_Time );

localtime_s(&timeinfo, &m_Time);

sprintf_s(szFileName, "%04d%02d%02d_%02d%02d%02d.mpg", timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);


strFileName += m_strModelPath;

strFileName += "\\";

strFileName += pFolder;

strFileName += "\\";

strFileName += szFileName;

}


FILE* pfRecord = nullptr;

if(fopen_s(&pfRecord, strFileName.c_str(), "wb+") == 0)

{

m_pDemuxer = new CDemuxer();

m_pDemuxer->InitData(pfRecord);

}

else

{

strFileName = "open file error,";

}


DeException exMsg(eRecordFilePath, this, false);

OUTPUT_DECODER("[%ld]<%d>%s", exMsg.m_szMsg, this, eRecordFilePath, strFileName.c_str());

exMsg.Execute();


return 0;

}


int CDecoder::StopLoadRecord()

{

if (m_pDemuxer != nullptr)

{

delete m_pDemuxer;

m_pDemuxer = nullptr;

SDL_Delay(10);

}


return 0;

}


int CDecoder::SetRecordPath(const char* pFolder)

{

if (pFolder)

{

m_strRecodFolder = pFolder;

}


return 0;

}


int CDecoder::SetPicturePath(const char* pFolder)

{

if (pFolder)

{

m_strPictureFolder = pFolder;

}


return 0;

}


int CDecoder::StreamSeek(int64_t nIncrease, int rel) 

{

int64_t nPos = (int64_t)( GetCutPts() + nIncrease) /** AV_TIME_BASE*/;


if (!seek_req) 

{

seek_pos = nPos;

seek_flags = rel < 0 ? AVSEEK_FLAG_BACKWARD : 0;

seek_req = 1;

}


return 0;

}


bool CDecoder::IsWindowInUse(const HWND& wnd)

{

if (m_pVideoc && m_pVideoc->pictq)

{

return (m_pVideoc->pictq->wndPlay == wnd);

}


return false;

}


以上是关于如何使用ffmpeg实现h264流传输+H264实现RTP传输数据的主要内容,如果未能解决你的问题,请参考以下文章

如何使用FFMPEG+H264实现RTP传输数据

使用 FFMpeg 将 FLV 流式传输到 RTMP,使用 H264 编解码器和 C++ API 到 flv.js

用 ts 包装 h264 流(传输流)

FFmpeg H264码流格式说明

H.264码流分析

(转)MP4文件两种格式AVC1和H264的区别及利用FFMPEG demux为h264码流事项