本例子实现的视频播放功能100行代码左右。根据ffmpeg官方的指导来写的。对于新手可以研究下。
还是直接上代码:
/*
*author tongli
*mail:2074929378@qq.com
*/
#include <stdio.h>
extern "C"{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "SDL.h"
#include "SDL_thread.h"
}
int main(int argc, char* argv[])
{
AVFormatContext *pFormatCtx;
int i, videoindex;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
SDL_Event event;
int got_picture;
struct SwsContext *img_convert_ctx;
AVPacket packet;
AVFrame *pFrame;
SDL_Rect rect;
AVPicture pict;
char *filename = "nihao.avi";
av_register_all();//注册全部的编解码器,协议等。本质上是初始化几个static的链表
avformat_network_init();
pFormatCtx = avformat_alloc_context();//此处必须进行初始化。
if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0){//根据文件名进行视频编码格式的判断
printf("Couldn't open input stream.\n");
return -1;
}
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)//获取流的一些信息
{
printf("Couldn't find stream information.\n");
return -1;
}
videoindex = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++){//找到视频流的索引
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoindex = i;
break;
}
}
if (videoindex == -1)
{
printf("Didn't find a video stream.\n");
return -1;
}
pCodecCtx = pFormatCtx->streams[videoindex]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);//找到解码器
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)//打开解码器
{
printf("Could not open codec.\n");
return -1;
}
pFrame = av_frame_alloc();
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);//初始化SDL
SDL_Surface *screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
SDL_Overlay *bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen);
int y_size = pCodecCtx->width * pCodecCtx->height;
//以前的函数形式是img_convet(...),现在由sws_getContexst(...)与sws_scale(...)共同来实现功能。就是将获取到的视频帧转换为目标图像格式
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
while (av_read_frame(pFormatCtx, &packet) >= 0)//获得数据包
{
if (packet.stream_index == videoindex)//检测数据包是不是视频包
{
avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);//所有的视频包是不是能组成一帧视频图像
if (got_picture)//如果能合成一帧视频图像
{
SDL_LockYUVOverlay(bmp);
pict.data[0] = bmp->pixels[0];
pict.data[1] = bmp->pixels[2];
pict.data[2] = bmp->pixels[1];
pict.linesize[0] = bmp->pitches[0];
pict.linesize[1] = bmp->pitches[2];
pict.linesize[2] = bmp->pitches[1];
sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0,
pCodecCtx->height,pict.data, pict.linesize);
SDL_UnlockYUVOverlay(bmp);
rect.x = 0;
rect.y = 0;
rect.w = pCodecCtx->width;
rect.h = pCodecCtx->height;
SDL_DisplayYUVOverlay(bmp, &rect);
SDL_Delay(40);//延迟40ms
}
}
//SDL事件循环
av_free_packet(&packet);
SDL_PollEvent(&event);
switch (event.type){
case SDL_QUIT:
SDL_Quit();
exit(0);
break;
default:
break;
}
}
sws_freeContext(img_convert_ctx);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
return 0;
}
源代码下载:100行左右的视频播放源码