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

📄 tutorial08.c

📁 ffmpeg开发指南
💻 C
📖 第 1 页 / 共 2 页
字号:
  SDL_CondSignal(is->pictq_cond);  SDL_UnlockMutex(is->pictq_mutex);}int queue_picture(VideoState *is, AVFrame *pFrame, double pts) {  VideoPicture *vp;  int dst_pix_fmt;  AVPicture pict;  static struct SwsContext *img_convert_ctx;  /* wait until we have space for a new pic */  SDL_LockMutex(is->pictq_mutex);  while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&	!is->quit) {    SDL_CondWait(is->pictq_cond, is->pictq_mutex);  }  SDL_UnlockMutex(is->pictq_mutex);  if(is->quit)    return -1;  // windex is set to 0 initially  vp = &is->pictq[is->pictq_windex];  /* allocate or resize the buffer! */  if(!vp->bmp ||     vp->width != is->video_st->codec->width ||     vp->height != is->video_st->codec->height) {    SDL_Event event;    vp->allocated = 0;    /* we have to do it in the main thread */    event.type = FF_ALLOC_EVENT;    event.user.data1 = is;    SDL_PushEvent(&event);    /* wait until we have a picture allocated */    SDL_LockMutex(is->pictq_mutex);    while(!vp->allocated && !is->quit) {      SDL_CondWait(is->pictq_cond, is->pictq_mutex);    }    SDL_UnlockMutex(is->pictq_mutex);    if(is->quit) {      return -1;    }  }  /* We have a place to put our picture on the queue */  /* If we are skipping a frame, do we set this to null      but still return vp->allocated = 1? */  if(vp->bmp) {    SDL_LockYUVOverlay(vp->bmp);        dst_pix_fmt = PIX_FMT_YUV420P;    /* point pict at the queue */    pict.data[0] = vp->bmp->pixels[0];    pict.data[1] = vp->bmp->pixels[2];    pict.data[2] = vp->bmp->pixels[1];        pict.linesize[0] = vp->bmp->pitches[0];    pict.linesize[1] = vp->bmp->pitches[2];    pict.linesize[2] = vp->bmp->pitches[1];        // Convert the image into YUV format that SDL uses    if(img_convert_ctx == NULL) {      int w = is->video_st->codec->width;      int h = is->video_st->codec->height;      img_convert_ctx = sws_getContext(w, h, 				       is->video_st->codec->pix_fmt, w, h, 				       dst_pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);      if(img_convert_ctx == NULL) {	fprintf(stderr, "Cannot initialize the conversion context!\n");	exit(1);      }    }    sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,	      0, is->video_st->codec->height, pict.data, pict.linesize);        SDL_UnlockYUVOverlay(vp->bmp);    vp->pts = pts;    /* now we inform our display thread that we have a pic ready */    if(++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) {      is->pictq_windex = 0;    }    SDL_LockMutex(is->pictq_mutex);    is->pictq_size++;    SDL_UnlockMutex(is->pictq_mutex);  }  return 0;}double synchronize_video(VideoState *is, AVFrame *src_frame, double pts) {  double frame_delay;  if(pts != 0) {    /* if we have pts, set video clock to it */    is->video_clock = pts;  } else {    /* if we aren't given a pts, set it to the clock */    pts = is->video_clock;  }  /* update the video clock */  frame_delay = av_q2d(is->video_st->codec->time_base);  /* if we are repeating a frame, adjust clock accordingly */  frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);  is->video_clock += frame_delay;  return pts;}uint64_t global_video_pkt_pts = AV_NOPTS_VALUE;/* These are called whenever we allocate a frame * buffer. We use this to store the global_pts in * a frame at the time it is allocated. */int our_get_buffer(struct AVCodecContext *c, AVFrame *pic) {  int ret = avcodec_default_get_buffer(c, pic);  uint64_t *pts = av_malloc(sizeof(uint64_t));  *pts = global_video_pkt_pts;  pic->opaque = pts;  return ret;}void our_release_buffer(struct AVCodecContext *c, AVFrame *pic) {  if(pic) av_freep(&pic->opaque);  avcodec_default_release_buffer(c, pic);}int video_thread(void *arg) {  VideoState *is = (VideoState *)arg;  AVPacket pkt1, *packet = &pkt1;  int len1, frameFinished;  AVFrame *pFrame;  double pts;  pFrame = avcodec_alloc_frame();  for(;;) {    if(packet_queue_get(&is->videoq, packet, 1) < 0) {      // means we quit getting packets      break;    }    if(packet->data == flush_pkt.data) {      avcodec_flush_buffers(is->video_st->codec);      continue;    }    pts = 0;    // Save global pts to be stored in pFrame    global_video_pkt_pts = packet->pts;    // Decode video frame    len1 = avcodec_decode_video(is->video_st->codec, pFrame, &frameFinished, 				packet->data, packet->size);    if(packet->dts == AV_NOPTS_VALUE        && pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) {      pts = *(uint64_t *)pFrame->opaque;    } else if(packet->dts != AV_NOPTS_VALUE) {      pts = packet->dts;    } else {      pts = 0;    }    pts *= av_q2d(is->video_st->time_base);    // Did we get a video frame?    if(frameFinished) {      pts = synchronize_video(is, pFrame, pts);      if(queue_picture(is, pFrame, pts) < 0) {	break;      }    }    av_free_packet(packet);  }  av_free(pFrame);  return 0;}int stream_component_open(VideoState *is, int stream_index) {  AVFormatContext *pFormatCtx = is->pFormatCtx;  AVCodecContext *codecCtx;  AVCodec *codec;  SDL_AudioSpec wanted_spec, spec;  if(stream_index < 0 || stream_index >= pFormatCtx->nb_streams) {    return -1;  }  // Get a pointer to the codec context for the video stream  codecCtx = pFormatCtx->streams[stream_index]->codec;  if(codecCtx->codec_type == CODEC_TYPE_AUDIO) {    // Set audio settings from codec info    wanted_spec.freq = codecCtx->sample_rate;    wanted_spec.format = AUDIO_S16SYS;    wanted_spec.channels = codecCtx->channels;    wanted_spec.silence = 0;    wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;    wanted_spec.callback = audio_callback;    wanted_spec.userdata = is;        if(SDL_OpenAudio(&wanted_spec, &spec) < 0) {      fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());      return -1;    }    is->audio_hw_buf_size = spec.size;  }  codec = avcodec_find_decoder(codecCtx->codec_id);  if(!codec || (avcodec_open(codecCtx, codec) < 0)) {    fprintf(stderr, "Unsupported codec!\n");    return -1;  }  switch(codecCtx->codec_type) {  case CODEC_TYPE_AUDIO:    is->audioStream = stream_index;    is->audio_st = pFormatCtx->streams[stream_index];    is->audio_buf_size = 0;    is->audio_buf_index = 0;        /* averaging filter for audio sync */    is->audio_diff_avg_coef = exp(log(0.01 / AUDIO_DIFF_AVG_NB));    is->audio_diff_avg_count = 0;    /* Correct audio only if larger error than this */    is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / codecCtx->sample_rate;    memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));    packet_queue_init(&is->audioq);    SDL_PauseAudio(0);    break;  case CODEC_TYPE_VIDEO:    is->videoStream = stream_index;    is->video_st = pFormatCtx->streams[stream_index];    is->frame_timer = (double)av_gettime() / 1000000.0;    is->frame_last_delay = 40e-3;    is->video_current_pts_time = av_gettime();    packet_queue_init(&is->videoq);    is->video_tid = SDL_CreateThread(video_thread, is);    codecCtx->get_buffer = our_get_buffer;    codecCtx->release_buffer = our_release_buffer;    break;  default:    break;  }}int decode_interrupt_cb(void) {  return (global_video_state && global_video_state->quit);}int decode_thread(void *arg) {  VideoState *is = (VideoState *)arg;  AVFormatContext *pFormatCtx;  AVPacket pkt1, *packet = &pkt1;  int video_index = -1;  int audio_index = -1;  int i;  is->videoStream=-1;  is->audioStream=-1;  global_video_state = is;  // will interrupt blocking functions if we quit!  url_set_interrupt_cb(decode_interrupt_cb);  // Open video file  if(av_open_input_file(&pFormatCtx, is->filename, NULL, 0, NULL)!=0)    return -1; // Couldn't open file  is->pFormatCtx = pFormatCtx;    // Retrieve stream information  if(av_find_stream_info(pFormatCtx)<0)    return -1; // Couldn't find stream information    // Dump information about file onto standard error  dump_format(pFormatCtx, 0, is->filename, 0);    // Find the first video stream  for(i=0; i<pFormatCtx->nb_streams; i++) {    if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO &&       video_index < 0) {      video_index=i;    }    if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO &&       audio_index < 0) {      audio_index=i;    }  }  if(audio_index >= 0) {    stream_component_open(is, audio_index);  }  if(video_index >= 0) {    stream_component_open(is, video_index);  }     if(is->videoStream < 0 || is->audioStream < 0) {    fprintf(stderr, "%s: could not open codecs\n", is->filename);    goto fail;  }  // main decode loop  for(;;) {    if(is->quit) {      break;    }    // seek stuff goes here    if(is->seek_req) {      int stream_index= -1;      int64_t seek_target = is->seek_pos;      if     (is->videoStream >= 0) stream_index = is->videoStream;      else if(is->audioStream >= 0) stream_index = is->audioStream;      if(stream_index>=0){	seek_target= av_rescale_q(seek_target, AV_TIME_BASE_Q, pFormatCtx->streams[stream_index]->time_base);      }      if(av_seek_frame(is->pFormatCtx, stream_index, seek_target, is->seek_flags) < 0) {		if (is->pFormatCtx->iformat->read_seek) {	  printf("format specific\n");	} else if(is->pFormatCtx->iformat->read_timestamp) {	  printf("frame_binary\n");	} else {	  printf("generic\n");	}	fprintf(stderr, "%s: error while seeking. target: %d, stream_index: %d\n", is->pFormatCtx->filename, seek_target, stream_index);      } else {	if(is->audioStream >= 0) {	  packet_queue_flush(&is->audioq);	  packet_queue_put(&is->audioq, &flush_pkt);	}	if(is->videoStream >= 0) {	  packet_queue_flush(&is->videoq);	  packet_queue_put(&is->videoq, &flush_pkt);	}      }      is->seek_req = 0;    }    if(is->audioq.size > MAX_AUDIOQ_SIZE ||       is->videoq.size > MAX_VIDEOQ_SIZE) {      SDL_Delay(10);      continue;    }    if(av_read_frame(is->pFormatCtx, packet) < 0) {      if(url_ferror(&pFormatCtx->pb) == 0) {	SDL_Delay(100); /* no error; wait for user input */	continue;      } else {	break;      }    }    // Is this a packet from the video stream?    if(packet->stream_index == is->videoStream) {      packet_queue_put(&is->videoq, packet);    } else if(packet->stream_index == is->audioStream) {      packet_queue_put(&is->audioq, packet);    } else {      av_free_packet(packet);    }  }  /* all done - wait for it */  while(!is->quit) {    SDL_Delay(100);  } fail:  {    SDL_Event event;    event.type = FF_QUIT_EVENT;    event.user.data1 = is;    SDL_PushEvent(&event);  }  return 0;}void stream_seek(VideoState *is, int64_t pos, int rel) {  if(!is->seek_req) {    is->seek_pos = pos;    is->seek_flags = rel < 0 ? AVSEEK_FLAG_BACKWARD : 0;    is->seek_req = 1;  }}int main(int argc, char *argv[]) {  SDL_Event       event;  double          pos;  VideoState      *is;  is = av_mallocz(sizeof(VideoState));  if(argc < 2) {    fprintf(stderr, "Usage: test <file>\n");    exit(1);  }  // Register all formats and codecs  av_register_all();    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {    fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());    exit(1);  }  // Make a screen to put our video#ifndef __DARWIN__  screen = SDL_SetVideoMode(640, 480, 0, 0);#else  screen = SDL_SetVideoMode(640, 480, 24, 0);#endif  if(!screen) {    fprintf(stderr, "SDL: could not set video mode - exiting\n");    exit(1);  }  pstrcpy(is->filename, sizeof(is->filename), argv[1]);  is->pictq_mutex = SDL_CreateMutex();  is->pictq_cond = SDL_CreateCond();  schedule_refresh(is, 40);  is->av_sync_type = DEFAULT_AV_SYNC_TYPE;  is->parse_tid = SDL_CreateThread(decode_thread, is);  if(!is->parse_tid) {    av_free(is);    return -1;  }  av_init_packet(&flush_pkt);  flush_pkt.data = "FLUSH";    for(;;) {    double incr, pos;    SDL_WaitEvent(&event);    switch(event.type) {    case SDL_KEYDOWN:      switch(event.key.keysym.sym) {      case SDLK_LEFT:	incr = -10.0;	goto do_seek;      case SDLK_RIGHT:	incr = 10.0;	goto do_seek;      case SDLK_UP:	incr = 60.0;	goto do_seek;      case SDLK_DOWN:	incr = -60.0;	goto do_seek;      do_seek:	if(global_video_state) {	  pos = get_master_clock(global_video_state);	  pos += incr;	  stream_seek(global_video_state, (int64_t)(pos * AV_TIME_BASE), incr);	}	break;      default:	break;      }      break;    case FF_QUIT_EVENT:    case SDL_QUIT:      is->quit = 1;      SDL_Quit();      exit(0);      break;    case FF_ALLOC_EVENT:      alloc_picture(event.user.data1);      break;    case FF_REFRESH_EVENT:      video_refresh_timer(event.user.data1);      break;    default:      break;    }  }  return 0;}

⌨️ 快捷键说明

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