来源:http://www.xuebuyuan.com/1466771.html

FFMPEG处理音频时间戳的主要逻辑

2013年12月09日 ⁄ 综合 ⁄ 共 2226字 ⁄ 字号 ⁄ 评论关闭
 

FFMPEG处理音频时间戳的主要逻辑是:

1. demux读取AVPacket。以输入flv为例,timebase是1/1000,第一个音频包可能是46,代表0.046秒。

2. decoder解码AVPacket为AVFrame,frame的pts为NOPTS,需要设置,否则后面都会有问题。主要是调用:av_rescale_delta:

AVRational in_tb = decoded_frame_tb;
AVRational fs_tb = (AVRational){1, ist->codec->sample_rate};
int duration = decoded_frame->nb_samples;
AVRational out_tb = (AVRational){1, ist->codec->sample_rate}; decoded_frame->pts = av_rescale_delta(in_tb, decoded_frame->pts, fs_tb, duration, &rescale_last_pts, out_tb);

相当于下面的逻辑:

// init the rescale_last_pts, set to 0 for the first decoded_frame->pts is 0
if (rescale_last_pts == AV_NOPTS_VALUE) {
rescale_last_pts = av_rescale_q(decoded_frame->pts, in_tb, fs_tb) + duration;
}
// the fs_tb equals to out_tb, so decoded_frame->pts equals to rescale_last_pts
decoded_frame->pts = av_rescale_q(rescale_last_pts, fs_tb, out_tb);;
rescale_last_pts += duration;

还可以简化为:

    /**
* for audio encoding, we simplify the rescale algorithm to following.
*/
if (rescale_last_pts == AV_NOPTS_VALUE) {
rescale_last_pts = 0;
}
decoded_frame->pts = rescale_last_pts;
rescale_last_pts += decoded_frame->nb_samples; // duration

实际上就是以nb_samples为时长,让pts为这个的总和,累积的samples就可以。因为默认把tb设置为sample_rate,所以samples数目就是pts。

3. filter过滤,实际上没有处理。

        // correct the pts
int64_t filtered_frame_pts = AV_NOPTS_VALUE;
if (picref->pts != AV_NOPTS_VALUE) {
// rescale the tb, actual the ofilter tb equals to ost tb,
// so this step canbe ignored and we always set start_time to 0.
filtered_frame_pts = av_rescale_q(picref->pts, ofilter->inputs[0]->time_base, ost->codec->time_base)
- av_rescale_q(start_time, AV_TIME_BASE_Q, ost->codec->time_base);
} // convert to frame
avfilter_copy_buf_props(filtered_frame, picref);
printf("filter -> picref_pts=%"PRId64", frame_pts=%"PRId64", filtered_pts=%"PRId64"\n",
picref->pts, filtered_frame->pts, filtered_frame_pts);
filtered_frame->pts = filtered_frame_pts;

4. encoder编码,主要是生成dts。

5. muxer输出前,需要做处理。譬如输出rtmp流,要将tb变为1/1000,flv的tb,也就是毫秒单位。

另外,时间戳从零开始。

    // correct the output, enforce start at 0.
static int64_t starttime = -1;
#if 1
if (starttime < 0) {
starttime = (pkt.dts < pkt.pts)? pkt.dts : pkt.pts;
}
pkt.dts -= starttime;
pkt.pts -= starttime;
#endif #if 1
// rescale audio ts to AVRational(1, 1000) for flv format.
AVRational flv_tb = (AVRational){1, 1000};
pkt.dts = av_rescale_q(pkt.dts, ost->codec->time_base, flv_tb);
pkt.pts = av_rescale_q(pkt.pts, ost->codec->time_base, flv_tb);
#endif

6. 最后一步,写入:

    ret = av_interleaved_write_frame(oc, &pkt);

就OK了。

FFMPEG处理音频时间戳的主要逻辑的更多相关文章

  1. [总结]FFMPEG视音频编解码零基础学习方法--转

    ffmpeg编解码学习   目录(?)[-] ffmpeg程序的使用ffmpegexeffplayexeffprobeexe 1 ffmpegexe 2 ffplayexe 3 ffprobeexe ...

  2. FFMPEG视音频编解码零基础学习方法

    在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频编解码的人,有的已经是有多年经验的“大神”,有的是刚开始学习的初学者.在和大家探讨的过程中,我忽然发现了一个问题:在“ ...

  3. 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)

    http://blog.csdn.net/leixiaohua1020/article/details/25430449 本文介绍一个最简单的基于FFMPEG的音频编码器.该编码器实现了PCM音频采样 ...

  4. FFMPEG视音频编解码零基础学习方法-b

    感谢大神分享,虽然现在还看不懂,留着大家一起看啦 PS:有不少人不清楚“FFmpeg”应该怎么读.它读作“ef ef em peg” 0. 背景知识 本章主要介绍一下FFMPEG都用在了哪里(在这里仅 ...

  5. [总结]FFMPEG视音频编解码零基础学习方法

    在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频编解码的人,有的已经是有多年经验的“大神”,有的是刚开始学习的初学者.在和大家探讨的过程中,我忽然发现了一个问题:在“ ...

  6. [Audio processing] FFMPEG转音频格式和采样率

    利用FFMPEG转音频格式和采样率 import os import string import subprocess as sp #Full path of ffmpeg FFMPEG_BIN = ...

  7. 【转】[总结]FFMPEG视音频编解码零基础学习方法

    在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频编解码的人,有的已经是有多年经验的“大神”,有的是刚开始学习的初学者.在和大家探讨的过程中,我忽然发现了一个问题:在“ ...

  8. 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——解码篇:(二)用ffmpeg解码音频

    其实这篇的内容和(一)用ffmpeg解码视频基本是一样的,重点还是给ffmpeg指定callback函数,而这个函数是从RTSP服务端那里获取音频数据的. 这里,解码音频的示例代码量之所以比解码视频的 ...

  9. C# 使用 ffmpeg 进行音频转码

    先放一下 ffmpeg 的官方文档以及下载地址: 官方文档:http://ffmpeg.org/ffmpeg.html 下载地址:http://ffmpeg.org/download.html 用 f ...

随机推荐

  1. Python进阶-I 初识函数(function)

    函数 在java中叫方法. 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print() ...

  2. Random Access Iterator 徐州网络赛(树形dp)

    Random Access Iterator \[ Time Limit: 4000 ms \quad Memory Limit: 262144 kB \] 题意 给出伪代码,问按着伪代码在树上跑,能 ...

  3. Office Tool Plus 安装Office

    Office Tool Plus 是一款集office 卸载安装管理,激活等多功能于一体的神器. 官网:https://otp.landian.vip/en-us/ 下载 安装 值得注意的是Retai ...

  4. django -- ORM查询

    前戏 在我们之前操作ORM中,你也许是启动Django项目,通过地址访问固定的函数,或者在pycharm里的python console里执行,第一种比较麻烦,而且每次都要启动项目,写路由,第二种虽然 ...

  5. selenium--获取HTML源码断言和URL地址

    获取HTML源码 from selenium import webdriver import unittest class Test_source(unittest.TestCase): def Te ...

  6. #lua中编写shader的方式

    lua中编写shader的方式 1. 字符串拼接 类似于下面这种 vertDefaultSource = "\n".."\n" .. "attribu ...

  7. Java 集合系列之六:工具类Collections和Arrays基本操作

    1. Collections Collections类主要是完成了两个主要功能 提供了若干简单而又有用的算法,比如排序,二分查找,求最大最小值等等. 提供对集合进行包装的静态方法.比如把指定的集合包装 ...

  8. ipv6转ipv4 NAT64与DNS64基本原理概述

    原文: https://blog.csdn.net/zhangjie1989/article/details/51464251 1.NAT64与 DNS64背景 在 IPv6网络的发展过程中,面临最大 ...

  9. 对C++11中的`移动语义`与`右值引用`的介绍与讨论

    本文主要介绍了C++11中的移动语义与右值引用, 并且对其中的一些坑做了深入的讨论. 在正式介绍这部分内容之前, 我们先介绍一下rule of three/five原则, 与copy-and-swap ...

  10. 写代码注意了,打死都不要用 User 这个单词

    阅读本文大概需要 4 分钟. 原文:http://t.cn/Eau2d0h 译文:http://21cto.com/article/2093 当你意识到你在项目开始时做的轻量.简单的设想竟然完全错了时 ...