实战--ffmpeg与sdl实现最简单的视频播放器

7 篇文章 0 订阅

流程:
解复用->解码->yuv->交给纹理->交给渲染器->播放。
其中前三步使用ffmpeg实现,后三步用sdl实现。

#include <stdio.h>
#include <SDL.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif

int main(int argc, char *argv[]) {

  int ret = -1;

  AVFormatContext *pFormatCtx = NULL; //for opening multi-media file

  int             i, videoStream;

  AVCodecContext  *pCodecCtxOrig = NULL; //codec context
  AVCodecContext  *pCodecCtx = NULL;

  struct SwsContext *sws_ctx = NULL;

  AVCodec         *pCodec = NULL; // the codecer
  AVFrame         *pFrame = NULL;
  AVPacket        packet;

  int             frameFinished;
  float           aspect_ratio;

  AVPicture  	  *pict  = NULL;

  SDL_Rect        rect;
  Uint32 	  pixformat; 

  //for render
  SDL_Window 	  *win = NULL;
  SDL_Renderer    *renderer = NULL;
  SDL_Texture     *texture = NULL;

  //set defualt size of window 
  int w_width = 640;
  int w_height = 480;

  if(argc < 2) {
    //fprintf(stderr, "Usage: command <file>\n");
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Usage: command <file>");
    return ret;
  }

  if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
    //fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not initialize SDL - %s\n", SDL_GetError());
    return ret;
  }

  //Register all formats and codecs
  av_register_all();

  // Open video file
  if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0){
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open video file!");
    goto __FAIL; // Couldn't open file
  }
  
  // Retrieve stream information
  if(avformat_find_stream_info(pFormatCtx, NULL)<0){
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to find stream infomation!");
    goto __FAIL; // Couldn't find stream information
  }
  
  // Dump information about file onto standard error
  av_dump_format(pFormatCtx, 0, argv[1], 0);
  
  // Find the first video stream
  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){
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Din't find a video stream!");
    goto __FAIL;// Didn't find a video stream
  }
  
  // Get a pointer to the codec context for the video stream
  pCodecCtxOrig=pFormatCtx->streams[videoStream]->codec;

  // Find the decoder for the video stream
  pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
  if(pCodec==NULL) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unsupported codec!\n");
    goto __FAIL; // Codec not found
  }

  // Copy context
  pCodecCtx = avcodec_alloc_context3(pCodec);
  if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,  "Couldn't copy codec context");
    goto __FAIL;// Error copying codec context
  }

  // Open codec
  if(avcodec_open2(pCodecCtx, pCodec, NULL)<0) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open decoder!\n");
    goto __FAIL; // Could not open codec
  }
  
  // Allocate video frame
  pFrame=av_frame_alloc();

  w_width = pCodecCtx->width;
  w_height = pCodecCtx->height;

  win = SDL_CreateWindow( "Media Player",
		          SDL_WINDOWPOS_UNDEFINED,
		  	  SDL_WINDOWPOS_UNDEFINED,
			  w_width, w_height,
			  SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);	  
  if(!win){
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create window by SDL");  
    goto __FAIL;
  }

  renderer = SDL_CreateRenderer(win, -1, 0);
  if(!renderer){
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create Renderer by SDL");  
    goto __FAIL;
  }

  pixformat = SDL_PIXELFORMAT_IYUV;
  texture = SDL_CreateTexture(renderer,
		    pixformat, 
		    SDL_TEXTUREACCESS_STREAMING,
		    w_width, 
		    w_height);

  // initialize SWS context for software scaling
  sws_ctx = sws_getContext(pCodecCtx->width,
			   pCodecCtx->height,
			   pCodecCtx->pix_fmt,
			   pCodecCtx->width,
			   pCodecCtx->height,
			   AV_PIX_FMT_YUV420P,
			   SWS_BILINEAR,
			   NULL,
			   NULL,
			   NULL
			   );

  pict = (AVPicture*)malloc(sizeof(AVPicture));
  avpicture_alloc(pict, 
		  AV_PIX_FMT_YUV420P, 
		  pCodecCtx->width, 
		  pCodecCtx->height);


  // Read frames and save first five frames to disk
  while(av_read_frame(pFormatCtx, &packet)>=0) {
    // Is this a packet from the video stream?
    if(packet.stream_index==videoStream) {
      // Decode video frame
      avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
      
      // Did we get a video frame?
      if(frameFinished) {

	// Convert the image into YUV format that SDL uses
	sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
		  pFrame->linesize, 0, pCodecCtx->height,
		  pict->data, pict->linesize);

	SDL_UpdateYUVTexture(texture, NULL, 
			     pict->data[0], pict->linesize[0],
			     pict->data[1], pict->linesize[1],
			     pict->data[2], pict->linesize[2]);
	
	// Set Size of Window
	rect.x = 0;
	rect.y = 0;
	rect.w = pCodecCtx->width;
	rect.h = pCodecCtx->height;

	SDL_RenderClear(renderer);
	SDL_RenderCopy(renderer, texture, NULL, &rect);
	SDL_RenderPresent(renderer);

      }
    }
    
    // Free the packet that was allocated by av_read_frame
    av_free_packet(&packet);

    /*
    SDL_Event event;
    SDL_PollEvent(&event);
    switch(event.type) {
    case SDL_QUIT:
      goto __QUIT;
      break;
    default:
      break;
    }
    */

  }

__QUIT:
  ret = 0;
  
__FAIL:
  // Free the YUV frame
  if(pFrame){
    av_frame_free(&pFrame);
  }
  
  // Close the codec
  if(pCodecCtx){
    avcodec_close(pCodecCtx);
  }

  if(pCodecCtxOrig){
    avcodec_close(pCodecCtxOrig);
  }
  
  // Close the video file
  if(pFormatCtx){
    avformat_close_input(&pFormatCtx);
  }

  if(pict){
    avpicture_free(pict);
    free(pict);
  }

  if(win){
    SDL_DestroyWindow(win);
  }

  if(renderer){
    SDL_DestroyRenderer(renderer);
  }

  if(texture){
    SDL_DestroyTexture(texture);
  }

  SDL_Quit();
  
  return ret;
}
  • 0
    点赞
  • 2
    收藏
  • 打赏
    打赏
  • 0
    评论
<p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; color: #e36c09; font-size: 20px;"><strong style="margin: 0px; padding: 0px;">我将带领大家一起来学习SDL2.0的编程知识,包括SDL2.0的编程框架、原理流程分析,几个核心对象、事件机制、扩展库的使用。</strong></span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #000000;"><strong style="margin: 0px; padding: 0px;">具体内容包括:</strong></span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #00b0f0;"><strong style="margin: 0px; padding: 0px;">1.搭建开发环境:VS2015或Qt5.9,共两套环境。</strong></span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #00b0f0;"><strong style="margin: 0px; padding: 0px;">2.核心对象编程:窗口、表面、渲染器、纹理、事件。</strong></span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #00b0f0;"><strong style="margin: 0px; padding: 0px;">3.扩展库的应用:SDL2_image,SDL2_mixer,SDL2_ttf(图像、音频、字库)</strong></span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #00b0f0;"><strong style="margin: 0px; padding: 0px;">4.官方案例实战:亲手练习官方推荐的几个案例,认真分析总结。</strong></span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"> </p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"> </p> <p style="box-sizing: border-box; margin: 0px; padding: 0px; font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-family: 'PingFang SC', 'Hiragino Sans GB', Arial, 'Microsoft YaHei', Verdana, Roboto, Noto, 'Helvetica Neue', sans-serif; color: #424242;">梅老师<span style="box-sizing: border-box; margin: 0px; padding: 0px;">从事音视频与流媒体行业18年</span>;曾在</span><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-family: 'PingFang SC', 'Hiragino Sans GB', Arial, 'Microsoft YaHei', Verdana, Roboto, Noto, 'Helvetica Neue', sans-serif; color: #974806;">永新视博、中科大洋、百度、美国Harris广播事业部</span><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-family: 'PingFang SC', 'Hiragino Sans GB', Arial, 'Microsoft YaHei', Verdana, Roboto, Noto, 'Helvetica Neue', sans-serif; color: #424242;">等公司就职,经验丰富;曾亲手主导广电直播全套项目,精通h.264/h.265/aac,曾亲自参与百度app上的网页播放器实战产品。</span></p> <p style="box-sizing: border-box; margin: 0px; padding: 0px; font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; color: #313d54; font-size: 16px; background-color: #ffffff;"> </p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"> </p> <p style="box-sizing: border-box; margin: 0px; padding: 0px; font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-family: 'PingFang SC', 'Hiragino Sans GB', Arial, 'Microsoft YaHei', Verdana, Roboto, Noto, 'Helvetica Neue', sans-serif; color: #424242;">目前全身心自主创业,主要<span style="box-sizing: border-box; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px;">聚焦音视频+流媒体行业</span></span>,<span style="box-sizing: border-box; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px;">精通音视频加密、流媒体在线转码快编等热门产品</span></span>。</span></p>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:博客之星2021 设计师:Hiro_C 返回首页
评论

打赏作者

、、、、南山小雨、、、、

分享对你有帮助,打赏一下吧!

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值