1测试开发环境是否正常
// ffmpeg-sample1.cpp : 定义控制台应用程序的入口点。 // #include <stdio.h> #define __STDC_CONSTANT_MACROS extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" }; int main1() { //av_register_all(); printf("\n<<Configuration>>\n%s", avcodec_configuration()); getchar(); return 0; }
2.测试解码将解码出来的yuv保存到文件里
// ffmpeg-sample1.cpp : 定义控制台应用程序的入口点。 // #include <stdio.h> #define __STDC_CONSTANT_MACROS extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" }; int main1() { //av_register_all(); printf("\n<<Configuration>>\n%s", avcodec_configuration()); getchar(); return 0; }
3.将sdl跟解码后的数据对接显示出视频
#include <stdio.h> #define __STDC_CONSTANT_MACROS extern "C"{ #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" #include "libavutil/imgutils.h" #include "SDL.h" }; int main(int argc, char* argv[]){ AVFormatContext *pFormatContext; int videoIndex; AVCodecContext *pContecCtx; AVCodec *pCodec; AVFrame *inputFrame, *outFrameYUV; AVPacket *packet; int y_size; int ret; int got_picture; struct SwsContext *img_convert_ctx; char filepath[] = "Titanic.mkv"; FILE *fp_yuv = fopen("output.yuv", "wb+"); av_register_all(); pFormatContext = avformat_alloc_context(); //先判断文件是否可读写 if (avformat_open_input(&pFormatContext, filepath, NULL, NULL) != 0){ printf("Couldn't find stream information.\n"); getchar(); return -1; } //查找文件相关信息 if (avformat_find_stream_info(pFormatContext, NULL) < 0){ printf("Couldn't find stream infomattion"); getchar(); return -1; } //找到视频帧的位置 videoIndex = -1; for (int i = 0; pFormatContext->nb_streams; i++){ if (pFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){ videoIndex = i; break; } } if (videoIndex == -1){ printf("Don't find a video stream"); return -1; } //找到对应流的解码器上下文 pContecCtx = pFormatContext->streams[videoIndex]->codec; //找到对应游戏的解码器 pCodec = avcodec_find_decoder(pContecCtx->codec_id); //是否支持该解码 if (pCodec == NULL){ printf("shuldn't support this type"); return -1; } // if (avcodec_open2(pContecCtx, pCodec, NULL) < 0){ printf("Could not open codec."); return -1; } inputFrame = av_frame_alloc(); outFrameYUV = av_frame_alloc(); const uint8_t *out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pContecCtx->width, pContecCtx->height)); avpicture_fill((AVPicture *)outFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pContecCtx->width, pContecCtx->height); packet = (AVPacket *)av_malloc(sizeof(AVPacket)); img_convert_ctx = sws_getContext(pContecCtx->width, pContecCtx->height, pContecCtx->pix_fmt, pContecCtx->width, pContecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); //sdl初始化 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { printf("Could not initialize SDL - %s\n", SDL_GetError()); return -1; } SDL_Window *screen = SDL_CreateWindow("simpleest ffmpeg", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, pContecCtx->width, pContecCtx->height, SDL_WINDOW_OPENGL); if (!screen){ printf("sdl :could create winwo %s", SDL_GetError()); return -1; } SDL_Renderer* sdlRender=SDL_CreateRenderer(screen, -1, 0); SDL_Texture *sdlTexture = SDL_CreateTexture(sdlRender, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, pContecCtx->width, pContecCtx->height); SDL_Rect sdlRect; sdlRect.x = 0; sdlRect.y = 0; sdlRect.w = pContecCtx->width; sdlRect.h = pContecCtx->height; while (av_read_frame(pFormatContext, packet)>=0){ //如果是视频帧 if (packet->stream_index == videoIndex){ //got_picture 非0 就说明可以解码 pFrame 就是一帧 ret = avcodec_decode_video2(pContecCtx, inputFrame, &got_picture, packet); if (ret < 0){ printf("decode Error\n"); continue; } if (got_picture){ //解码后YUV格式的视频像素数据保存在AVFrame的date[0] ..但这些像素值不是连续存储的,每行有效像素之后存储了一些无效像素...因此需要用sws_scale()进行转换,转换后去除了无效数据。 sws_scale(img_convert_ctx, (const uint8_t* const*)inputFrame->data, inputFrame->linesize, 0, pContecCtx->height, outFrameYUV->data, outFrameYUV->linesize); /* y_size = pContecCtx->width*pContecCtx->height; fwrite(outFrameYUV->data[0], 1, y_size, fp_yuv); //Y fwrite(outFrameYUV->data[1], 1, y_size / 4, fp_yuv); //U fwrite(outFrameYUV->data[2], 1, y_size / 4, fp_yuv); //V */ SDL_UpdateYUVTexture(sdlTexture, &sdlRect, outFrameYUV->data[0], outFrameYUV->linesize[0], outFrameYUV->data[1], outFrameYUV->linesize[1], outFrameYUV->data[2], outFrameYUV->linesize[2]); SDL_RenderClear(sdlRender); SDL_RenderCopy(sdlRender, sdlTexture, NULL, &sdlRect); SDL_RenderPresent(sdlRender); //SDL End----------------------- //Delay 40ms SDL_Delay(40); } } av_free_packet(packet); } getchar(); //sws_freeContext(img_convert_ctx); fclose(fp_yuv); av_frame_free(&inputFrame); av_frame_free(&outFrameYUV); avcodec_close(pContecCtx); avformat_close_input(&pFormatContext); return 0; }
期间遇到一个问题:
1>SDL2main.lib(SDL_windows_main.obj) : error LNK2019: 无法解析的外部符号 SDL_main,该符号在函数 main_utf8 中被引用
1>E:\public-ffmpeg\project\ffmpeg-sample-player\x64\Debug\Win32Project1.exe : fatal error LNK1120:
解决的办法是:将 int main() 改为 int main(int argc,char* argv[])