⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tutorial05.c

📁 ffmpeg开发指南
💻 C
📖 第 1 页 / 共 2 页
字号:
// tutorial05.c// A pedagogical video player that really works!//// Code based on FFplay, Copyright (c) 2003 Fabrice Bellard, // and a tutorial by Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de)// Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1// Use//// gcc -o tutorial05 tutorial05.c -lavutil -lavformat -lavcodec -lz -lm `sdl-config --cflags --libs`// to build (assuming libavformat and libavcodec are correctly installed, // and assuming you have sdl-config. Please refer to SDL docs for your installation.)//// Run using// tutorial05 myvideofile.mpg//// to play the video.#include <avcodec.h>#include <avformat.h>#include <SDL.h>#include <SDL_thread.h>#ifdef __MINGW32__#undef main /* Prevents SDL from overriding main() */#endif#include <stdio.h>#include <math.h>#define SDL_AUDIO_BUFFER_SIZE 1024#define MAX_AUDIOQ_SIZE (5 * 16 * 1024)#define MAX_VIDEOQ_SIZE (5 * 256 * 1024)#define AV_SYNC_THRESHOLD 0.01#define AV_NOSYNC_THRESHOLD 10.0#define FF_ALLOC_EVENT   (SDL_USEREVENT)#define FF_REFRESH_EVENT (SDL_USEREVENT + 1)#define FF_QUIT_EVENT (SDL_USEREVENT + 2)#define VIDEO_PICTURE_QUEUE_SIZE 1typedef struct PacketQueue {  AVPacketList *first_pkt, *last_pkt;  int nb_packets;  int size;  SDL_mutex *mutex;  SDL_cond *cond;} PacketQueue;typedef struct VideoPicture {  SDL_Overlay *bmp;  int width, height; /* source height & width */  int allocated;  double pts;} VideoPicture;typedef struct VideoState {  AVFormatContext *pFormatCtx;  int             videoStream, audioStream;  double          audio_clock;  AVStream        *audio_st;  PacketQueue     audioq;  uint8_t         audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];  unsigned int    audio_buf_size;  unsigned int    audio_buf_index;  AVPacket        audio_pkt;  uint8_t         *audio_pkt_data;  int             audio_pkt_size;  int             audio_hw_buf_size;    double          frame_timer;  double          frame_last_pts;  double          frame_last_delay;  double          video_clock; ///<pts of last decoded frame / predicted pts of next decoded frame  AVStream        *video_st;  PacketQueue     videoq;  VideoPicture    pictq[VIDEO_PICTURE_QUEUE_SIZE];  int             pictq_size, pictq_rindex, pictq_windex;  SDL_mutex       *pictq_mutex;  SDL_cond        *pictq_cond;    SDL_Thread      *parse_tid;  SDL_Thread      *video_tid;  char            filename[1024];  int             quit;} VideoState;SDL_Surface     *screen;/* Since we only have one decoding thread, the Big Struct   can be global in case we need it. */VideoState *global_video_state;void packet_queue_init(PacketQueue *q) {  memset(q, 0, sizeof(PacketQueue));  q->mutex = SDL_CreateMutex();  q->cond = SDL_CreateCond();}int packet_queue_put(PacketQueue *q, AVPacket *pkt) {  AVPacketList *pkt1;  if(av_dup_packet(pkt) < 0) {    return -1;  }  pkt1 = av_malloc(sizeof(AVPacketList));  if (!pkt1)    return -1;  pkt1->pkt = *pkt;  pkt1->next = NULL;    SDL_LockMutex(q->mutex);  if (!q->last_pkt)    q->first_pkt = pkt1;  else    q->last_pkt->next = pkt1;  q->last_pkt = pkt1;  q->nb_packets++;  q->size += pkt1->pkt.size;  SDL_CondSignal(q->cond);    SDL_UnlockMutex(q->mutex);  return 0;}static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block){  AVPacketList *pkt1;  int ret;  SDL_LockMutex(q->mutex);    for(;;) {        if(global_video_state->quit) {      ret = -1;      break;    }    pkt1 = q->first_pkt;    if (pkt1) {      q->first_pkt = pkt1->next;      if (!q->first_pkt)	q->last_pkt = NULL;      q->nb_packets--;      q->size -= pkt1->pkt.size;      *pkt = pkt1->pkt;      av_free(pkt1);      ret = 1;      break;    } else if (!block) {      ret = 0;      break;    } else {      SDL_CondWait(q->cond, q->mutex);    }  }  SDL_UnlockMutex(q->mutex);  return ret;}double get_audio_clock(VideoState *is) {  double pts;  int hw_buf_size, bytes_per_sec, n;    pts = is->audio_clock; /* maintained in the audio thread */  hw_buf_size = is->audio_buf_size - is->audio_buf_index;  bytes_per_sec = 0;  n = is->audio_st->codec->channels * 2;  if(is->audio_st) {    bytes_per_sec = is->audio_st->codec->sample_rate * n;  }  if(bytes_per_sec) {    pts -= (double)hw_buf_size / bytes_per_sec;  }  return pts;}int audio_decode_frame(VideoState *is, uint8_t *audio_buf, int buf_size, double *pts_ptr) {  int len1, data_size, n;  AVPacket *pkt = &is->audio_pkt;  double pts;  for(;;) {    while(is->audio_pkt_size > 0) {      data_size = buf_size;      len1 = avcodec_decode_audio2(is->audio_st->codec, 				  (int16_t *)audio_buf, &data_size, 				  is->audio_pkt_data, is->audio_pkt_size);      if(len1 < 0) {	/* if error, skip frame */	is->audio_pkt_size = 0;	break;      }      is->audio_pkt_data += len1;      is->audio_pkt_size -= len1;      if(data_size <= 0) {	/* No data yet, get more frames */	continue;      }      pts = is->audio_clock;      *pts_ptr = pts;      n = 2 * is->audio_st->codec->channels;      is->audio_clock += (double)data_size /	(double)(n * is->audio_st->codec->sample_rate);      /* We have data, return it and come back for more later */      return data_size;    }    if(pkt->data)      av_free_packet(pkt);    if(is->quit) {      return -1;    }    /* next packet */    if(packet_queue_get(&is->audioq, pkt, 1) < 0) {      return -1;    }    is->audio_pkt_data = pkt->data;    is->audio_pkt_size = pkt->size;    /* if update, update the audio clock w/pts */    if(pkt->pts != AV_NOPTS_VALUE) {      is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;    }  }}void audio_callback(void *userdata, Uint8 *stream, int len) {  VideoState *is = (VideoState *)userdata;  int len1, audio_size;  double pts;  while(len > 0) {    if(is->audio_buf_index >= is->audio_buf_size) {      /* We have already sent all our data; get more */      audio_size = audio_decode_frame(is, is->audio_buf, sizeof(is->audio_buf), &pts);      if(audio_size < 0) {	/* If error, output silence */	is->audio_buf_size = 1024;	memset(is->audio_buf, 0, is->audio_buf_size);      } else {	is->audio_buf_size = audio_size;      }      is->audio_buf_index = 0;    }    len1 = is->audio_buf_size - is->audio_buf_index;    if(len1 > len)      len1 = len;    memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);    len -= len1;    stream += len1;    is->audio_buf_index += len1;  }}static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) {  SDL_Event event;  event.type = FF_REFRESH_EVENT;  event.user.data1 = opaque;  SDL_PushEvent(&event);  return 0; /* 0 means stop timer */}/* schedule a video refresh in 'delay' ms */static void schedule_refresh(VideoState *is, int delay) {  SDL_AddTimer(delay, sdl_refresh_timer_cb, is);}void video_display(VideoState *is) {  SDL_Rect rect;  VideoPicture *vp;  AVPicture pict;  float aspect_ratio;  int w, h, x, y;  int i;  vp = &is->pictq[is->pictq_rindex];  if(vp->bmp) {    if(is->video_st->codec->sample_aspect_ratio.num == 0) {      aspect_ratio = 0;    } else {      aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio) *	is->video_st->codec->width / is->video_st->codec->height;    }    if(aspect_ratio <= 0.0) {      aspect_ratio = (float)is->video_st->codec->width /	(float)is->video_st->codec->height;    }    h = screen->h;    w = ((int)rint(h * aspect_ratio)) & -3;    if(w > screen->w) {      w = screen->w;      h = ((int)rint(w / aspect_ratio)) & -3;    }    x = (screen->w - w) / 2;    y = (screen->h - h) / 2;        rect.x = x;    rect.y = y;    rect.w = w;    rect.h = h;    SDL_DisplayYUVOverlay(vp->bmp, &rect);  }}void video_refresh_timer(void *userdata) {  VideoState *is = (VideoState *)userdata;  VideoPicture *vp;  double actual_delay, delay, sync_threshold, ref_clock, diff;    if(is->video_st) {    if(is->pictq_size == 0) {      schedule_refresh(is, 1);    } else {      vp = &is->pictq[is->pictq_rindex];      delay = vp->pts - is->frame_last_pts; /* the pts from last time */      if(delay <= 0 || delay >= 1.0) {	/* if incorrect delay, use previous one */	delay = is->frame_last_delay;      }      /* save for next time */      is->frame_last_delay = delay;      is->frame_last_pts = vp->pts;      /* update delay to sync to audio */      ref_clock = get_audio_clock(is);      diff = vp->pts - ref_clock;      /* Skip or repeat the frame. Take delay into account	 FFPlay still doesn't "know if this is the best guess." */      sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD;      if(fabs(diff) < AV_NOSYNC_THRESHOLD) {	if(diff <= -sync_threshold) {	  delay = 0;	} else if(diff >= sync_threshold) {	  delay = 2 * delay;	}      }      is->frame_timer += delay;      /* computer the REAL delay */      actual_delay = is->frame_timer - (av_gettime() / 1000000.0);      if(actual_delay < 0.010) {	/* Really it should skip the picture instead */	actual_delay = 0.010;      }      schedule_refresh(is, (int)(actual_delay * 1000 + 0.5));      /* show the picture! */      video_display(is);            /* update queue for next picture! */      if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) {	is->pictq_rindex = 0;      }      SDL_LockMutex(is->pictq_mutex);      is->pictq_size--;      SDL_CondSignal(is->pictq_cond);      SDL_UnlockMutex(is->pictq_mutex);    }  } else {    schedule_refresh(is, 100);  }}      void alloc_picture(void *userdata) {  VideoState *is = (VideoState *)userdata;  VideoPicture *vp;  vp = &is->pictq[is->pictq_windex];  if(vp->bmp) {    // we already have one make another, bigger/smaller    SDL_FreeYUVOverlay(vp->bmp);  }  // Allocate a place to put our YUV image on that screen  vp->bmp = SDL_CreateYUVOverlay(is->video_st->codec->width,				 is->video_st->codec->height,				 SDL_YV12_OVERLAY,				 screen);  vp->width = is->video_st->codec->width;  vp->height = is->video_st->codec->height;    SDL_LockMutex(is->pictq_mutex);  vp->allocated = 1;  SDL_CondSignal(is->pictq_cond);  SDL_UnlockMutex(is->pictq_mutex);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -