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 <string.h>
#include <math.h>
#include <chrono> //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/fifo.h"
#include "libavutil/samplefmt.h"
#include "libavutil/time.h"
#include "libavutil/timestamp.h"
#include "libavutil/channel_layout.h"
#include "libavutil/opt.h"
#include "libswresample/swresample.h"
#include "SDL2\SDL.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libswresample/swresample.h>
#include <SDL2/SDL.h>
#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;
}
最後,我司專注于流媒體和AI技術的研發與拓展,歡迎各界朋友莅臨指導或技術交流,QQ:2470425326。