最近需要实现一个功能:利用FFmpeg将编码出来的视频流和音频流混合封装成TS格式,然后通过自定义协议将TS流发送出去。因为发送协议是自己定义的,FFmpeg不支持这种网络协议,不能用它内置的协议。后来发现原来FFmpeg也支持将输出的流回调到给上层去处理,下面简单讲一下实现的流程。
首先,我们按照把流输出到文件的方式来处理,但是有小小的不同,下面是初始化输出流的代码:
AVOutputFormat *m_fmt;
AVFormatContext *m_oc;
AVStream *audio_st, *video_st;
typedef struct _capstuff {
UINT m_nPixelFormat; //enum PixelFormat
int m_videobitrate; //视频码率
int m_audiobitrate; //音频码率
int m_audio_samplerate; //音频采样率
int m_framerate; //帧率
UINT m_nRCMode; //视频的编码模式,0--CBR, 1--VBR
UINT m_StreamType; //0--Video, 1--Audio, 2--Video+Audio
UINT m_IFramesIntervals; //关键帧间距
UINT m_nVideoCodec;//CodecID
UINT m_nAudioCodec; //CodecID
UINT m_Quant; //质量系数
char m_szFormatName[64]; //流的封装格式,比如TS,MOV,MPG,MP4
BOOL m_bDefaultCodec;
}CAPSTUFF;
CAPSTUFF m_CapStuff[8]; //最多支持8个输入流
BOOL CVideoDevice::InitFFmpeg()
{
m_fmt = NULL;
m_oc = NULL;
/* initialize libavcodec, and register all codecs and formats */
av_register_all();
char outputformat[64] = {0};
strcpy(outputformat, "1.ts"); //默认使用TS
/* allocate the output media context */
avformat_alloc_output_context2(&m_oc, NULL, NULL, outputformat);
if (!m_oc) {
TRACE("Could not deduce output format from file extension: using MPEG.\n");
avformat_alloc_output_context2(&m_oc, NULL, "mpeg", "1.mpg");
}
if (!m_oc) {
return FALSE;
}
m_fmt = m_oc->oformat;
#if 0
const char *filename = "D:\\camera_ffmpeg.ts";
strcpy(m_oc->filename, filename);
#else
const char *filename = outputformat;
unsigned char* outbuffer = NULL;
outbuffer = (unsigned char*)av_malloc(65536);
AVIOContext *avio_out = avio_alloc_context(outbuffer, 65536, 0, this, NULL, write_buffer,NULL);
m_oc->pb = avio_out;
m_oc->flags |= AVFMT_FLAG_CUSTOM_IO;
m_oc->flags |= AVFMT_FLAG_FLUSH_PACKETS;
m_fmt->flags |= AVFMT_NOFILE; //不生成文件
#endif
/* add the audio and video streams using the default format codecs
and initialize the codecs */
video_st = NULL;
audio_st = NULL;
if (m_fmt->video_codec != CODEC_ID_NONE) {
video_st = add_video_stream(m_oc,
(CodecID)m_CapStuff[0].m_