1:ffmpeg解码流程 拆包,构建队列,解码,同步,显示

//计算视频Frame的显示时间
//获取pts
pts = 0;
//decodec video frame
avcodec_decode_video2(AVFormatContxt*,AVFrame,int*,AVPacket);
if( (pts = av_frame_get_best_effort_timestamp(pFrame)) == AV_NOPTS_VALUSE )
{

}
else
{
  pts = 0;
}

pts *= av_q2d(pFormatCtx->Stream[video_index]->time_base);

if(frameFinished)
{
  //计算需要的时间延时
  //pts = synchronize_video(⋯⋯);

}

//synchronize_video(^)函数的实现
//video_clock是视频播放到当前帧时的已播放的时间长度。在synchronize函数中,如果没有得到该帧的PTS就用当前的video_clock来近似,然后更新video_clock的值。到这里已经知道了video中frame的显示时间了(秒为单位)
double synchronize_video(VideoState *is,AVFrame *src_frame,double pts)
{
  double frame_delay;
  if(pts != 0)
  {
    is->video_clock = pts;//保存pts
  }
  else
  {
    pts = is->video_clock;//否者使用上一次保存的pts
  }
  //更新video clock
  frame_delay = av_q2d(is->video_ctx->time_base);
  frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
  is->video_clock += frame_delay;
  return pts;
}

//获取Audio Clock
//Audio Clock,也就是Audio的播放时长,可以在Audio时更新Audio Clock。在函数audio_decode_frame中解码新的packet,这是可以设置Auddio clock为该packet的PTS
if (pkt.pts != AV_NOPTS_VALUE)
{
  audio_state->audio_clock = av_q2d(audio_state->stream->time_base) * pkt.pts;
}
//由于一个packet中可以包含多个帧,packet中的PTS比真正的播放的PTS可能会早很多,可以根据Sample Rate 和 Sample Format来计算出该packet中的数据可以播放的时长,再次更新Audio clock 。
// 每秒钟音频播放的字节数 sample_rate * channels * sample_format(一个sample占用的字节数)
audio_state->audio_clock += static_cast<double>(data_size) / (2 * audio_state->stream->codec->channels *
audio_state->stream->codec->sample_rate);
//上面乘以2是因为sample format是16位的无符号整型,占用2个字节。
for(;;)
{
  while(is->audio_pkt_size > 0)
  {
    int got_frame = 0;
    len1 = avcodec_decode_audio(is->audio_ctx,&is_audio_frame,&got_frame,pkt);
    if(len1 < 0)
    {
      is->audio_pkt_size = 0;
      break;
    }
    data_size = 0;
    if(got_frame)
    {  
      data_size = av_sample_get_buffer_size(NULL,is->audio_ctx->channels,is->audio_frame.nb_samples,is->audio_ctx->sample_fmt,1);
      assert(data_size <= buf_size);
      memcpy(audio_buf,is->audio_frame.data[0],data_size);
    }
    is->audio_pkt_data += len1;
    is->audio_pkt_size -= len1;
    if(data_size <= 0)
    continue;
    pts = is->audio_clock;
    *pts_pts = pts;
    n = 2 * is->audio_ctx->channles;
    is->audio_clock += (double)data_size / double(n * is->audio_ctx->sample_rate);
    return data_size;
  }
  if(pke->data)
    av_free_packet(pkt);
  if(is->quit)
  {
    return -1;
  }

  //read next packet
  if(packet_queue_get(&is_audioqmpkt,1) < 0)
    return -1;
  is->audio_pkt_data = pkt->data;
  is->audio_pkt_size = pkt->size;
  if(pkt->pts != AV_NOPTS_VALUE)
  {
    is->audio_clock = av_q2d(is->audio_st->time_base)* pkt->pts;
  }
}

//有了Audio clock后,在外面获取该值的时候却不能直接返回该值,因为audio缓冲区的可能还有未播放的数据,需要减去这部分的时间

double AudioStatue::Get_audip_clock()
{
  int hw_buf_size = audio_buff_size - audio_buff_index;
  int bytes_pre_sec = steam->codec->sample_rate * audio_ctx->channels * 2;
  double pts = (audio_clock - static_cast<double>(hw_buf_size)/bytes_pre_sec;
  return pts;
}

//audio缓冲区中剩余的数据除以每秒播放的音频数据得到剩余数据的播放时间,从Audio clock中减去这部分的值就是当前的audio的播放时长。

//同步
1:用当前的pts - 上一播放帧的pts得到一个时延
2:用当前帧的pts和Audio Clock进行比较,来判断视频的播放速度是快了还是慢了
3:根据上一步判断结果,设置播放下一阵的延迟时间

double current_pts = *(double*)video->frame->opaque;
double delay = current_pts - video->frame_last_pts;
if(delay < = 0 || delay >= 1.0)
delay = video->frame_last_delay;

video->frame_last_delay = delay;
video->frame_last_pts = current_pts;
//根据Audio Clock来判断Video播放的快慢
double ref_clock = media->audio->get_audio_clock();

double diff = current_pts - ref_clock;

double threshold = (delay > SYNC_THRESHOLD) ? delay L SYNV_THRESHOLD;

//调整播放下一阵的延迟时间,以实现同步
if(fabs(diff) < NOSYNC_THRESHOLD)
{
  if(diff <= -threashold)//慢了
  delay = 0;
  else if(diff >= threshold)
  delay *= 2;
}

video->frame_timer += delay;
double actual_delay = video->frame_timer = static_cast<double>(av_gettime())/1000000.0;
if(actual_delay <= 0.010)
  actual_delay = 0.010;

//设置下一帧的播放延迟
schedule_refresh(media,static_cast<int>(actual_delay * 1000 + 0.5));

ffmpeg同步的更多相关文章

  1. FFmpeg学习6:视音频同步

    在上一篇文章中,视频和音频是各自独立播放的,并不同步.本文主要描述了如何以音频的播放时长为基准,将视频同步到音频上以实现视音频的同步播放的.主要有以下几个方面的内容 视音频同步的简单介绍 DTS 和 ...

  2. ffmpeg转码MPEG2-TS的音视频同步机制分析

    http://blog.chinaunix.net/uid-26000296-id-3483782.html 一.FFmpeg忽略了adaptation_field()数据 FFmpeg忽略了包含PC ...

  3. Ffmpeg和SDL如何同步视频(转)

    ong> PTS和DTS 幸运的是,音频和视频流都有一些关于以多快速度和什么时间来播放它们的信息在里面.音频流有采样,视频流有每秒的帧率.然而,如果我们只是简单的通过数帧和乘以帧率的方式来同步视 ...

  4. Ffmpeg和SDL如何同步音频

    ong> 同步音頻 现在我们已经有了一个比较像样的播放器.所以让我们看一下还有哪些零碎的东西没处理.上次,我们掩饰了一点同步问题,也就是同步音频到视频而不是其它的同步方式.我们将采用和视频一样的 ...

  5. [ffmpeg] 多输入滤波同步方式(framesync)

    滤波也不总是单一的输入,也存在对多个输入流进行滤波的需求,最常见的就是对视频添加可视水印,水印的组成通常为原视频以及作为水印的图片或者小动画,在ffmpeg中可以使用overlay滤波器进行水印添加. ...

  6. FFmpeg简易播放器的实现-音视频同步

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10284653.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

  7. ffmpeg 2.3版本号, 关于ffplay音视频同步的分析

    近期学习播放器的一些东西.所以接触了ffmpeg,看源代码的过程中.就想了解一下ffplay是怎么处理音视频同步的,之前仅仅大概知道通过pts来进行同步,但对于怎样实现却不甚了解,所以想借助这个机会, ...

  8. FFmpeg 入门(6):音频同步

    本文转自:FFmpeg 入门(6):音频同步 | www.samirchen.com 音频同步 上一节我们做了将视频同步到音频时钟,这一节我们反过来,将音频同步到视频.首先,我们要实现一个视频时钟来跟 ...

  9. FFmpeg 入门(5):视频同步

    本文转自:FFmpeg 入门(5):视频同步 | www.samirchen.com 视频如何同步 在之前的教程中,我们已经可以开始播放视频了,也已经可以开始播放音频了,但是视频和音频的播放还未同步, ...

随机推荐

  1. cmd 环境变量设置的简单方法

    1.查看当前所有可用的环境变量:输入 set 即可查看. 2.查看某个环境变量:输入 “set 变量名”即可,比如想查看temp变量的值,即输入 set temp 3.修改环境变量 :输入 “set ...

  2. 为iOS设计:图形和性能

    在之前的文章里,我们探讨了基于多种不同技术来实现自定义的UIButton,当然不同的技术所涉及到的代码复杂度和难度也不一样.但是我也有意提到了基于不同方法的实现所体现出的性能表现也不一一相同. [在屏 ...

  3. squeeze()

    一.说明 B = squeeze(A),B与A有相同的元素,但所有只有一行或一列的维度(a singleton dimension)被去除掉了.A singleton dimension的特征是siz ...

  4. 如何从github上clone项目源码-linux

    前言 github是目前较为流行的代码托管网站,linux系统是目前开发人员较为常用的操作系统.项目实现的过程中用到一些经典好用的源代码,可以从github上clone,本文主要介绍linux系统命令 ...

  5. uva1482:Playing With Stones (SG函数)

    题意:有N堆石子,每次可以取一堆的不超过半数的石子,没有可取的为输. 思路:假设只有一堆,手推出来,数量x可以表示为2^p-1形式的必输. 但是没什么用,因为最后要的不是0和1,而是SG函数:所以必输 ...

  6. Luogu 3245 大数

    Luogu 3245 大数 开始就想 \(10\) 进制 \(hash\) ,\(Hash(r)\equiv Hash(l-1)\cdot 10^{r-l+1}\) ,感觉没什么美妙的性质啊... 然 ...

  7. C#对文件I/O的一些基本操作

    System.IO命名空间包含允许在数据流和文件上进行同步,异步及写入的类型,下面是关于c#文件的I/O基本操作讲解,需要的朋友可以参考下 文件是一些永久存储及具有特定顺序的字节组成的一个有序的,具有 ...

  8. WPF开源界面库及控件

    WPF开源项目 WPF有很多优秀的开源项目,我以为大家都知道,结果,问了很多人,其实他们不知道.唉,太可惜了! 先介绍两个比较牛逼的界面库 1.MaterialDesignInXamlToolkit ...

  9. V4L2 subdev

    除了通过v4l2_subdev_ops结构体暴露kernel API,V4L2 sub-devices也可以被用户空间应用直接控制.v4l-subdevX的设备节点可以在/dev下被创建来直接访问su ...

  10. Apache和Nginx的Rewrite规则对比

    一.Apache的rewrite 1.Rewrite规则简介: Rewirte主要的功能就是实现URL的跳转,它的正则表达式是基于Perl语言.可基于服务器级的(httpd.conf)和目录级的(.h ...