FFmpeg相信做流媒体的都不陌生,这就不累述了。最近在各方资源里we闻到有人说”FFmpeg是做音视频编解码的“,说的太狭隘了,了解FFmpeg的一般也都知道VLC,VLC是一套以FFmpeg为基础的完整流媒体解决方案,行内称:VLC是汽车,FFMpeg就是发动机”,这就很形象的描述了FFmpeg的功能。FFmpeg是集音视频采集、音视频演示数据处理、解复用、编码解码、渲染等完整流媒体框架,内合入ffplay可实现渲染播放。webrtc是功能上与之并驾齐驱的一套架构,它合入一些新的编码标准,如音频的OPUS标准,SIP信令协议等,后续再以webrtc为框架写一些blog。
不说废话,先上代码。程序中将视频流decode成YUV420P格式,合入SDL2渲染播放。虽然是完整代码,目的为学术交流和技术共享,无意培养伸手党。代码中解决ffmpeg中新老接口对接,其它都是按decode的一般流程解码,如有不妥之处,欢迎指正。技术交流群:479245235,欢迎各界精英论道。
#include "stdio.h"
#include "iostream"
#include "stdlib.h"
#include
#include
#include //C++11时间类标准模板库
#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavfilter/avfilter.h"
#include "libavutil/imgutils.h"
#include "libavutil/fifo.h"
#include "libavutil/samplefmt.h"
#include "libavutil/time.h"
#include "libavutil/timestamp.h"
#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libswresample/swresample.h"
#include "SDL2\SDL.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include
#include
#include
#include
#include
#include
#ifdef __cplusplus
};
#endif
#endif
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
int main()
{
const char *fname;
char errbuf[256] = { 0 };
int iRes = 0;
int vindex = -1;
AVFormatContext *fctx = NULL;
AVCodecContext *cctx = NULL;
AVCodec *c = NULL;
AVPacket *pkt = NULL;
AVFrame *fr = NULL;
AVFrame *yuv = NULL;
uint8_t *buf = NULL;
int vsize;
struct SwsContext *imgCtx = NULL;
SDL_Window *sw = NULL;
SDL_Renderer *sr = NULL;
SDL_Texture *ste = NULL;
SDL_Rect srect = { 0 };
// av_register_all(); //ffmpeg 4.0 After no
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
cout << "SDL init failed!" << endl;
return -1;
}
fctx = avformat_alloc_context();
if ((iRes = avformat_open_input(&fctx, fname, NULL, NULL)) != 0)
{
cout << "File open failed!" << endl;
return -1;
}
if (avformat_find_stream_info(fctx, NULL) < 0)
{
cout << "Stream find failed!\n";
return -1;
}
av_dump_format(fctx, -1, fname, NULL);
for (int i = 0; i < fctx->nb_streams; i++)
{
if (fctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
vindex = i;
}
if (vindex == -1)
{
cout << "Codec find failed!" << endl;
return -1;
}
cctx = avcodec_alloc_context3(NULL);
if (avcodec_parameters_to_context(cctx, fctx->streams[vindex]->codecpar) < 0)
{
cout << "Copy stream failed!" << endl;
return -1;
}
c = avcodec_find_decoder(cctx->codec_id);
if (!c) {
cout << "Find Decoder failed!" << endl;
return -1;
}
if (avcodec_open2(cctx, c, NULL) != 0) {
cout << "Open codec failed!" << endl;
return -1;
}
sw = SDL_CreateWindow("video", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 680, 540, SDL_WINDOW_OPENGL);
sr = SDL_CreateRenderer(sw, -1, 0);
ste = SDL_CreateTexture(sr, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, cctx->width, cctx->height);
if (!sw || !sr || !ste) {
cout << "Create SDL windows failed!" << endl;
return -1;
}
srect.w = cctx->width;
srect.h = cctx->height;
imgCtx = sws_getContext(cctx->width, cctx->height, cctx->pix_fmt, cctx->width, cctx->height, AV_PIX_FMT_YUV420P,
SWS_BICUBIC, NULL, NULL, NULL);
if (!imgCtx) {
cout << "Get swscale context failed!" << endl;
return -1;
}
pkt = av_packet_alloc();
fr = av_frame_alloc();
yuv = av_frame_alloc();
vsize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, cctx->width, cctx->height, 1);
buf = (uint8_t *)av_malloc(vsize);
av_image_fill_arrays(yuv->data, yuv->linesize,buf, AV_PIX_FMT_YUV420P, cctx->width, cctx->height, 1);
while (av_read_frame(fctx, pkt) >= 0) {
if (pkt->stream_index == vindex) {
if ((iRes = avcodec_send_packet(cctx, pkt)) != 0)
{
cout << "Send video stream packet failed!" << endl;
av_strerror(iRes, errbuf, 256);
return -5;
}
if ((iRes = avcodec_receive_frame(cctx, fr)) != 0)
{
cout << "Receive video frame failed!\n";
av_strerror(iRes, errbuf, 256);
return -6;
}
sws_scale(imgCtx, fr->data, fr->linesize, 0, cctx->height, yuv->data, yuv->linesize);
SDL_UpdateTexture(ste, &srect, yuv->data[0], yuv->linesize[0]);
SDL_RenderClear(sr);
SDL_RenderCopy(sr, ste, NULL, NULL);
SDL_RenderPresent(sr);
}
}
av_free(buf);
av_frame_free(&yuv);
av_frame_free(&fr);
av_packet_free(&pkt);
sws_freeContext(imgCtx);
SDL_DestroyTexture(ste);
SDL_DestroyRenderer(sr);
SDL_DestroyWindow(sw);
SDL_Quit();
avcodec_free_context(&cctx);
avformat_close_input(&fctx);
avformat_free_context(fctx);
return 0;
}
本人从事流媒体研发多年,资深流媒体CTO,QQ:2470425326;公司为音视频解决方案供应商,位于上海市浦东新区张江镇张衡路1299号凯信国际广场2号楼,真诚欢迎各界伙伴前来参观和洽谈合作。