最近遇到好几个人在问ffmpeg如何处理网络流,刚好前段时间也在做这方面,抽空整理了下,把主要代码发出来,希望对大家有用。为简单处理,我这里只简单介绍UDP接收TS流,其实只要是socket接收的都可以类似处理。
#include "utils.h"
#include <pthread.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h>UdpQueue recvqueue;
UdpParam udpParam;//注册av_read_frame的回调函数,这里只是最简处理,实际应用中应加上出错处理,超时等待...
int read_data(void *opaque, uint8_t *buf, int buf_size) { int size = buf_size; int ret; // printf("read data %d\n", buf_size); do { ret = get_queue(&recvqueue, buf, buf_size); } while (ret);// printf("read data Ok %d\n", buf_size);
return size; }#define BUF_SIZE 4096*500
int main(int argc, char** argv) {
init_queue(&recvqueue, 1024*500);
udpParam.argv = argv;
udpParam.queue = &recvqueue; uint8_t *buf = av_mallocz(sizeof(uint8_t)*BUF_SIZE); //UDP接收线程 pthread_t udp_recv_thread; pthread_create(&udp_recv_thread, NULL, udp_ts_recv, &udpParam); pthread_detach(udp_recv_thread);
av_register_all();
AVCodec *pVideoCodec, *pAudioCodec;
AVCodecContext *pVideoCodecCtx = NULL; AVCodecContext *pAudioCodecCtx = NULL; AVIOContext * pb = NULL; AVInputFormat *piFmt = NULL; AVFormatContext *pFmt = NULL;//step1:申请一个AVIOContext
pb = avio_alloc_context(buf, BUF_SIZE, 0, NULL, read_data, NULL, NULL); if (!pb) { fprintf(stderr, "avio alloc failed!\n"); return -1; } //step2:探测流格式 if (av_probe_input_buffer(pb, &piFmt, "", NULL, 0, 0) < 0) { fprintf(stderr, "probe failed!\n"); return -1; } else { fprintf(stdout, "probe success!\n"); fprintf(stdout, "format: %s[%s]\n", piFmt->name, piFmt->long_name); }pFmt = avformat_alloc_context();
pFmt->pb = pb; //step3:这一步很关键 //step4:打开流 if (avformat_open_input(&pFmt, "", piFmt, NULL) < 0) { fprintf(stderr, "avformat open failed.\n"); return -1; } else { fprintf(stdout, "open stream success!\n"); } //以下就和文件处理一致了 if (av_find_stream_info(pFmt) < 0) { fprintf(stderr, "could not fine stream.\n"); return -1; }av_dump_format(pFmt, 0, "", 0);
int videoindex = -1;
int audioindex = -1; for (int i = 0; i < pFmt->nb_streams; i++) { if ( (pFmt->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) && (videoindex < 0) ) { videoindex = i; } if ( (pFmt->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) && (audioindex < 0) ) { audioindex = i; } }if (videoindex < 0 || audioindex < 0) {
fprintf(stderr, "videoindex=%d, audioindex=%d\n", videoindex, audioindex); return -1; }AVStream *pVst,*pAst;
pVst = pFmt->streams[videoindex]; pAst = pFmt->streams[audioindex];pVideoCodecCtx = pVst->codec;
pAudioCodecCtx = pAst->codec;pVideoCodec = avcodec_find_decoder(pVideoCodecCtx->codec_id);
if (!pVideoCodec) { fprintf(stderr, "could not find video decoder!\n"); return -1; } if (avcodec_open(pVideoCodecCtx, pVideoCodec) < 0) { fprintf(stderr, "could not open video codec!\n"); return -1; }pAudioCodec = avcodec_find_decoder(pAudioCodecCtx->codec_id);
if (!pAudioCodec) { fprintf(stderr, "could not find audio decoder!\n"); return -1; } if (avcodec_open(pAudioCodecCtx, pAudioCodec) < 0) { fprintf(stderr, "could not open audio codec!\n"); return -1; }int got_picture;
uint8_t samples[AVCODEC_MAX_AUDIO_FRAME_SIZE*3/2]; AVFrame *pframe = avcodec_alloc_frame(); AVPacket pkt; av_init_packet(&pkt);while(1) {
if (av_read_frame(pFmt, &pkt) >= 0) {if (pkt.stream_index == videoindex) {
fprintf(stdout, "pkt.size=%d,pkt.pts=%lld, pkt.data=0x%x.", pkt.size, pkt.pts,(unsigned int)pkt.data); avcodec_decode_video2(pVideoCodecCtx, pframe, &got_picture, &pkt); if (got_picture) { fprintf(stdout, "decode one video frame!\n"); } }else if (pkt.stream_index == audioindex) { int frame_size = AVCODEC_MAX_AUDIO_FRAME_SIZE*3/2; if (avcodec_decode_audio3(pAudioCodecCtx, (int16_t *)samples, &frame_size, &pkt) >= 0) { fprintf(stdout, "decode one audio frame!\n"); } } av_free_packet(&pkt); } }av_free(buf);
av_free(pframe); free_queue(&recvqueue); return 0; }