1測試開發環境是否正常
windows
// 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保存到文件裏ide
// 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 中被引用ui
1>E:\public-ffmpeg\project\ffmpeg-sample-player\x64\Debug\Win32Project1.exe : fatal error LNK1120:this
解決的辦法是:將 int main() 改成 int main(int argc,char* argv[])spa