FFmpeg基础:SDL渲染显示视频流数据
#include <>
#include <>
#include <libavcodec/>
#include <libavformat/>
#include <libswscale/>
#include <libswresample/>
#include <libavutil/>
#include <>
//@1视频文件的地址
int main(int argc, char *argv[]) {
int ret = -1;
int quit = 0;
int videoStream;
AVFormatContext *pFormatCtx = NULL;
//视频解码上下文,解码器
AVCodecContext *pSourceCodecCtx = NULL;
AVCodec *pSourceCodec = NULL;
//图像转换上下文
struct SwsContext *sws_ctx = NULL;
//图像数据格式
uint8_t *dst_data[4] = { 0 };
int dst_linesize[4] = { 0 };
AVFrame *pFrame = NULL;
AVPacket packet;
//视频宽高
int w_width = 640;
int w_height = 480;
//SDL渲染用
int pixformat;
SDL_Rect rect;
SDL_Window *win;
SDL_Renderer *renderer;
SDL_Texture *texture;
SDL_Event event;
SDL_AudioSpec wanted_spec, spec;
if (argc < 2) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Usage: command <file>");
return ret;
}
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not initialize SDL - %s\n", SDL_GetError());
return ret;
}
//打开视频上下文
if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open multi-media file");
goto __FAIL; // Couldn't open file
}
//获取流信息信息
if (avformat_find_stream_info(pFormatCtx, NULL)<0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find stream information ");
goto __FAIL;
}
//查找视频流
videoStream = -1;
for (int i = 0; i<pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
videoStream < 0) {
videoStream = i;
}
}
if (videoStream == -1) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, " Didn't find a video stream ");
goto __FAIL;
}
//查找视频流的解码器
pSourceCodec = avcodec_find_decoder(pFormatCtx->streams[videoStream]->codecpar->codec_id);
if (pSourceCodec == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unsupported codec!");
goto __FAIL;
}
//创建解码器的上下文,并拷贝参数
pSourceCodecCtx = avcodec_alloc_context3(pSourceCodec);
ret = avcodec_parameters_to_context(pSourceCodecCtx, pFormatCtx->streams[videoStream]->codecpar);
if (ret < 0) {
printf("Failed to copy in_stream codecpar to codec context\n");
goto __FAIL;
}
//打开解码器
if (avcodec_open2(pSourceCodecCtx, pSourceCodec, NULL)<0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open audio decoder!");
goto __FAIL;
}
pFrame = av_frame_alloc();
w_width = pSourceCodecCtx->width;
w_height = pSourceCodecCtx->height;
//创建输出窗口
win = SDL_CreateWindow("SDL Video Player",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
w_width, w_height,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (!win) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create window!");
goto __FAIL;
}
//SDL渲染器
renderer = SDL_CreateRenderer(win, -1, 0);
if (!renderer) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create renderer!");
goto __FAIL;
}
//创建显示帧
pixformat = SDL_PIXELFORMAT_IYUV;
texture = SDL_CreateTexture(renderer,
pixformat,
SDL_TEXTUREACCESS_STREAMING,
w_width,
w_height);
if (!texture)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create Texture!");
goto __FAIL;
}
//转换图像格式
sws_ctx = sws_getContext(pSourceCodecCtx->width,
pSourceCodecCtx->height,
pSourceCodecCtx->pix_fmt,
pSourceCodecCtx->width,
pSourceCodecCtx->height,
AV_PIX_FMT_YUV420P,
SWS_BILINEAR,
NULL,
NULL,
NULL);
ret = av_image_alloc(
dst_data, dst_linesize, pSourceCodecCtx->width, pSourceCodecCtx->height,
AV_PIX_FMT_YUV420P, 1);
//读取数据帧并渲染
while (av_read_frame(pFormatCtx, &packet) >= 0)
{
if (packet.stream_index == videoStream)
{
ret = avcodec_send_packet(pSourceCodecCtx, &packet);
if (ret < 0)
{
continue;
}
ret = avcodec_receive_frame(pSourceCodecCtx, pFrame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
ret = 0;
continue;
}
if (ret < 0) {
continue;
}
//对图像进行缩放
sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
pFrame->linesize, 0, pSourceCodecCtx->height,
dst_data, dst_linesize);
//渲染图像
SDL_UpdateYUVTexture(texture, NULL,
dst_data[0], dst_linesize[0],
dst_data[1], dst_linesize[1],
dst_data[2], dst_linesize[2]);
rect.x = 0;
rect.y = 0;
rect.w = pSourceCodecCtx->width;
rect.h = pSourceCodecCtx->height;
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, &rect);
SDL_RenderPresent(renderer);
SDL_Delay(1000 / 30);
av_packet_unref(&packet);
}
//处理SDL事件
SDL_PollEvent(&event);
}
__FAIL:
//清理分配的数据
av_freep(&dst_data[0]);
if (pFormatCtx)
{
avformat_close_input(&pFormatCtx);
}
if (pFrame) {
av_frame_free(&pFrame);
}
if (pSourceCodecCtx)
{
avcodec_close(pSourceCodecCtx);
}
if (pSourceCodecCtx) {
avcodec_close(pSourceCodecCtx);
}
if (pFormatCtx) {
avformat_close_input(&pFormatCtx);
}
if (win) {
SDL_DestroyWindow(win);
}
if (renderer) {
SDL_DestroyRenderer(renderer);
}
if (texture) {
SDL_DestroyTexture(texture);
}
SDL_Quit();
return ret;
}