* 學習自雷神的博客和視頻,圖片來自他的課件,雷神博客:* bash
http://blog.csdn.NET/leixiaohua1020/數據結構
ffmpeg的庫ide
ffmpeg的執行流程函數
ffmpeg 解碼相關結構體工具
SDL顯示YUV圖像流程:post
#include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> #include <stdio.h> #include <SDL/SDL.h> #include <SDL/SDL_thread.h> int main(int argc, char *argv[]) { AVFormatContext *pFormatCtx = NULL; int i, videoStream; AVCodecContext *pCodecCtx = NULL; AVCodec *pCodec = NULL; AVFrame *pFrame = NULL; AVPacket packet; int frameFinished; AVDictionary *optionDict = NULL; struct SwsContext *sws_ctx = NULL; SDL_Overlay *bmp = NULL; SDL_Surface *screen = NULL; SDL_Rect rect; SDL_Event event; if(argc < 2){ fprintf(stderr, "Usage: test <file> \n"); exit(1); } av_register_all(); if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)){ fprintf(stderr,"Could not initialize SDL - %s " + *SDL_GetError()); exit(1); } /* *打開一個文件 */ if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0) return -1; /* *爲pFormatCtx->streams填充上正確的信息 */ if(avformat_find_stream_info(pFormatCtx, NULL) < 0) return -1; /* *手工調試函數,將文件信息在終端輸出 */ av_dump_format(pFormatCtx, 0, argv[1], 0); videoStream=-1; for ( i = 0; i < pFormatCtx->nb_streams; i++) if(pFormatCtx -> streams[i] -> codec -> codec_type == AVMEDIA_TYPE_VIDEO) { videoStream = i; break; } if(videoStream == -1) return -1; /* *從 vedio stream 中獲取對應的解碼器上下文的指針 */ pCodecCtx = pFormatCtx -> streams[videoStream] -> codec; /* *根據 codec_id 找到對應的解碼器 */ pCodec = avcodec_find_decoder(pCodecCtx -> codec_id); if(pCodec == NULL){ fprintf(stderr, "Unsupported codec ! \n"); return -1; } /* * 打開解碼器 */ if(avcodec_open2(pCodecCtx, pCodec, &optionDict) <0 ) return -1; /* * 爲frame 申請內存 */ pFrame = av_frame_alloc(); #ifdef __DARWIN__ screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0); #else screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 24, 0); #endif // __DARWIN__ if(!screen){ fprintf(stderr, "SDL : could not set video mode - exiting \n"); exit(1); } /* * 申請一個 overlay , 將 yuv數據給 screen */ bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen); sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL); i = 0; while (av_read_frame(pFormatCtx, &packet) >= 0){ if(packet.stream_index == videoStream){ //爲視頻流解碼 avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); if(frameFinished){ SDL_LockYUVOverlay(bmp); AVPicture pict; 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(sws_ctx, (uint8_t const * 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(10); } } av_free_packet(&packet); SDL_PollEvent(&event); switch (event.type) { case SDL_QUIT: SDL_Quit(); exit(0); break; default: break; } } av_free(pFrame); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); return 0; }
編譯:學習
gcc -o playvedio playvedio.c -lavutil -lavformat -lavcodec -lavutil -lswscale -lSDL
運行:ui
./playvedio 文件路徑+文件名