FFmpeg+SDL 视频播放器
生活随笔
收集整理的這篇文章主要介紹了
FFmpeg+SDL 视频播放器
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
參考鏈接:《基于 FFmpeg + SDL 的視頻播放器的制作》課程的視頻_雷霄驊(leixiaohua1020)的專欄-CSDN博客_雷霄驊ffmpeg視頻教程
雷神的基于 FFmpeg + SDL 的視頻播放器的制作到這里快進入尾聲,下面還有一節添加圖形界面的課程,不得不說,雷神的錄播課講的非常詳細,令人欽佩。
關于雷神的基于 FFmpeg + SDL 的視頻播放器的制作的源代碼,我發現在他在界面.h265,h.264的文件時,視頻的播放速度還算是正常,但是在播放flv,mp4等封裝格式的文件時,速度會比較慢,不是正常的速度,這個他在視頻中有講過修改方法,不過在課件的源代碼中給出的不是修改過后的,這里給出正確的修改代碼(具體修改方式,雷神在http://www.iqiyi.com/w_19rruoxurx.html視頻教程中有所提及)
#include "stdafx.h"extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h"//SDL #include "sdl/SDL.h" #include "sdl/SDL_thread.h"};//Refresh Event #define SFM_REFRESH_EVENT (SDL_USEREVENT + 1)int thread_exit = 0; //定義一個線程結束標志int sfp_refresh_thread(void* opaque) {while (thread_exit == 0) {SDL_Event event;event.type = SFM_REFRESH_EVENT;SDL_PushEvent(&event);SDL_Delay(40);}return 0; }int _tmain(int argc, _TCHAR* argv[]) {AVFormatContext* pFormatCtx;int i, videoindex;AVCodecContext* pCodecCtx; //保存了視頻(音頻)編解碼相關信息。AVCodec* pCodec;char filepath[] = "屌絲男士.mov";int frame_cnt = 0;//注冊組件+初始化av_register_all(); avformat_network_init();//函數用來申請AVFormatContext類型變量并初始化默認參數,分配內存空間pFormatCtx = avformat_alloc_context();//打開視頻流文件if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0) {printf("Couldn't open input stream.(無法打開輸入流)\n");return -1;}//獲取視頻文件信息if (av_find_stream_info(pFormatCtx) < 0){printf("Couldn't find stream information.(無法獲取流信息)\n");return -1;}//設置一個視頻幀索引videoindex = -1;for (i = 0; i < pFormatCtx->nb_streams; i++) //nb_streams:輸入視頻的AVStream 個數if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) //streams:輸入視頻的AVStream []數組{videoindex = i; //判斷文件是視頻流還是音頻流,把其中的視頻流獲取出來break;}if (videoindex == -1){printf("Didn't find a video stream.(沒有找到視頻流)\n");return -1;}pCodecCtx = pFormatCtx->streams[videoindex]->codec; //codec:該流對應的AVCodecContextpCodec = avcodec_find_decoder(pCodecCtx->codec_id); //avcodec_find_decoder():查找解碼器; pCodecCtx->codec_id 編解碼器IDif (pCodec == NULL){printf("Codec not found.(沒有找到解碼器)\n");return -1;}//打開解碼器,參數為AVCodecContext和對應的解碼器IDif (avcodec_open2(pCodecCtx, pCodec, NULL) < 0){printf("Could not open codec.(無法打開解碼器)\n");return -1;}AVFrame* pFrame, * pFrameYUV; //存儲一幀解碼后像素(采樣)數據pFrame = avcodec_alloc_frame(); //為解碼幀分配內存pFrameYUV = avcodec_alloc_frame();//av_malloc()內存分配,uint8_t = unsigned char無符號字符型//avpicture_get_size()計算這個格式的圖片,需要多少字節來存儲uint8_t* out_buffer = (uint8_t*)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));/*pFrameYUV和out_buffer都是已經申請到的一段內存, 但是pFrameYUV只是申請了一段結構體內存, 結構體里面的值是空的, 我們需要使用avpicture_fill()函數來使得pFrameYUV和out_buffer關聯起來,pFrameYUV里面使用的是out_buffer所指向的內存空間.*/avpicture_fill((AVPicture*)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);//------------SDL----------------//初始化if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {printf("Could not initialize SDL - %s\n", SDL_GetError());return -1;}int screen_w = 0, screen_h = 0;SDL_Window* screen;//SDL 2.0 Support for multiple windowsscreen_w = pCodecCtx->width;screen_h = pCodecCtx->height;//創建一個窗口screen = SDL_CreateWindow("Simplest ffmpeg player's Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,screen_w, screen_h,SDL_WINDOW_OPENGL);if (!screen) {printf("SDL: could not create window - exiting:%s\n", SDL_GetError());return -1;}//創建一個渲染器SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);//IYUV: Y + U + V (3 planes)//YV12: Y + V + U (3 planes)SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height);SDL_Rect sdlRect; //創建一個矩形結構體,分別給左上角的坐標以及矩形框的寬和高sdlRect.x = 0;sdlRect.y = 0;sdlRect.w = screen_w;sdlRect.h = screen_h;int ret, got_picture;//分配一幀壓縮編碼數據的內存AVPacket* packet = (AVPacket*)av_malloc(sizeof(AVPacket));//Output Info-----------------------------printf("File Information(文件信息)---------------------\n");//av_dump_format()打印關于輸入或輸出格式的詳細信息av_dump_format(pFormatCtx, 0, filepath, 0);printf("-------------------------------------------------\n");//詳解:https://blog.csdn.net/MACMACip/article/details/105450185struct SwsContext* img_convert_ctx; img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);//--------------//創建一個線程SDL_Thread* video_tid = SDL_CreateThread(sfp_refresh_thread, NULL, NULL);////Event LoopSDL_Event event;for (;;) {//WaitSDL_WaitEvent(&event);if (event.type == SFM_REFRESH_EVENT) {//------------------------------//在這里判斷是不是視頻幀,如果是就直接跳出循環while (1) {if (av_read_frame(pFormatCtx, packet) < 0) {thread_exit = 1;}if (packet->stream_index == videoindex) {break;}}//解碼一幀壓縮數據ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);if (ret < 0) {printf("Decode Error.(解碼錯誤)\n");return -1;}if (got_picture) {sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);//printf("Decoded frame index: %d\n", frame_cnt);//frame_cnt++;//SDL---------------------------SDL_UpdateTexture(sdlTexture, &sdlRect, pFrameYUV->data[0], pFrameYUV->linesize[0]);SDL_RenderClear(sdlRenderer);SDL_RenderCopy(sdlRenderer, sdlTexture, &sdlRect, &sdlRect);SDL_RenderPresent(sdlRenderer);//SDL End-----------------------//av_free_packet(packet);}av_free_packet(packet); //釋放}}sws_freeContext(img_convert_ctx); SDL_Quit(); //退出線程//--------------av_free(out_buffer);av_free(pFrameYUV);avcodec_close(pCodecCtx);avformat_close_input(&pFormatCtx);return 0; }總結
以上是生活随笔為你收集整理的FFmpeg+SDL 视频播放器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 200行Html5+CSS3+JS代码实
- 下一篇: python 调用qrcode库实现二维