(原)从mp4,flv文件中解析出h264和aac,送解码器解码失败
转载请注明出处:http://www.cnblogs.com/lihaiping/p/5285166.html
今天在做本地文件解码测试,发现从mp4,flv文件中读出来的帧数据,h264和aac帧直接送解码器解码,发现解码失败,但文件放在pc上用ffplay和vlc却都能播放,而且这个测试的视频文件是用ffmpeg.exe进行转码出来的,所以应该不存在解码不了的问题,那问题在哪呢?
百度了下,网上有人说mp4文件里面封装的h264有两种格式:h264和avc1:
而这两种格式的差别是:
AVC1 描述:H.264 bitstream without start codes.一般通过ffmpeg转码生成的视频,是不带起始码0×00000001的。
H264 描述:H.264 bitstream with start codes.一般对于一下HDVD等电影的压制格式,是带有起始码0×00000001的。
所以我又用vlc播放查看了下,原来真的是avc1,这才发现原来自己接触了这么久的流媒体,连avc1都没听过,哎,悲哀。
那要如何才能解码呢?同时我查看了一下,ffmpeg中对h264的avc1并没有设置单独的解码器,只有一个h264的解码器codeid,那它是怎么实现解码avc1的?又是如何区分的呢?
问题1:如何解码?
在这里其实有人遇到了和我一样的问题:http://stackoverflow.com/questions/11330764/ffmpeg-cant-decode-h264-stream-frame-data
同时还有人在论坛上讨论该如何解决:http://bbs.csdn.net/topics/390538510
有人说avc1是原始的NAL打包格式,就是开始的若干字节(1,2,4字节)是NAL的长度,而不是start_code,此时必须借助某个全局的数据来获得编码器的profile,level,PPS,SPS等信息才可以解码。
既然这样,那我要如何才能获得pps,sps等这些信息呢?有人写过:http://blog.csdn.net/gavinr/article/details/7183499,在这篇文章里面,需要注意几个之前没认真了解的新地方:
1)pps及sps不能从packet获得,而是保存在AVCodecContext的extradata数据域中
2)如何从extradata中解析出sps及pps呢?ffmpeg中提供了一个流过滤器"h264_mp4toannexb"可以完成
解决方法为:使用ffmpeg提供的h264_mp4toannexb流过滤器进行解决:具体方法可以参考:http://blog.csdn.net/leixiaohua1020/article/details/11800877
问题2:ffmpeg中没有对avc1使用单独的解码器,而是和h264同样使用同一个解码器?那它是如何区分的呢?
这个问题,需要仔细翻看一下ffmpeg的源代码了,在ff_h264_decode_init函数中有这样的一段代码:
if (avctx->extradata_size > && avctx->extradata) {
ret = ff_h264_decode_extradata(h, avctx->extradata, avctx->extradata_size);
if (ret < ) {
ff_h264_free_context(h);
return ret;
}
}
继续往下看,看ff_h264_decode_extradata函数中做了些什么?
int ff_h264_decode_extradata(H264Context *h, const uint8_t *buf, int size)
{
AVCodecContext *avctx = h->avctx;
int ret; if (!buf || size <= )
return -; if (buf[0] == 1) {
int i, cnt, nalsize;
const unsigned char *p = buf; h->is_avc = 1; if (size < ) {
av_log(avctx, AV_LOG_ERROR,
"avcC %d too short\n", size);
return AVERROR_INVALIDDATA;
}
/* sps and pps in the avcC always have length coded with 2 bytes,
* so put a fake nal_length_size = 2 while parsing them */
h->nal_length_size = ;
// Decode sps from avcC
cnt = *(p + ) & 0x1f; // Number of sps
p += ;
for (i = ; i < cnt; i++) {
nalsize = AV_RB16(p) + ;
if(nalsize > size - (p-buf))
return AVERROR_INVALIDDATA;
ret = decode_nal_units(h, p, nalsize, );
if (ret < ) {
av_log(avctx, AV_LOG_ERROR,
"Decoding sps %d from avcC failed\n", i);
return ret;
}
p += nalsize;
}
// Decode pps from avcC
cnt = *(p++); // Number of pps
for (i = ; i < cnt; i++) {
nalsize = AV_RB16(p) + ;
if(nalsize > size - (p-buf))
return AVERROR_INVALIDDATA;
ret = decode_nal_units(h, p, nalsize, );
if (ret < ) {
av_log(avctx, AV_LOG_ERROR,
"Decoding pps %d from avcC failed\n", i);
return ret;
}
p += nalsize;
}
// Store right nal length size that will be used to parse all other nals
h->nal_length_size = (buf[] & 0x03) + ;
} else {
h->is_avc = ;
ret = decode_nal_units(h, buf, size, );
if (ret < )
return ret;
}
return size;
}
所以再这里h264的解码器是通过AVCodecContext的extradata在ff_h264_decode_init的时候,进行了区分,同时也进行初始化解码。
=================================================================
aac解码失败的问题:
http://blog.csdn.net/leixiaohua1020/article/details/39767055 这篇文章说了,视音频分离器(Demuxer),并不适用于一些格式。对于MP3编码的音频是没有问题的。但是在分离MP4/FLV/MKV等一些格式中的AAC编码的码流的时候,得到的AAC码流是不能播放的。原因是存储AAC数据的AVPacket的data字段中的数据是不包含7字节ADTS文件头的“砍头”的数据,是无法直接解码播放的(当然如果在这些数据前面手工加上7字节的ADTS文件头的话,就可以播放了)。
adts?又是一个新概念,怎么解决?谷歌不在问度娘,http://blog.csdn.net/tx3344/article/details/7414543,这篇文章介绍了adts的概念。
本来是想通过和h264的avc1方案一样来解决,但发现使用aac_adtstoasc流过滤器是行不通的,因为他一直是返回0,于是我看了一下ffmpeg中这个函数的源码,原来这个函数的源码就是返回0的.测试结果也是解码不了。
后面找到了一篇文章:http://blog.chinaunix.net/uid-24922718-id-3692670.html,本来想参考着这里面的方法实现:
char bits[] = {};
int sample_index = , channel = ;
char temp = ;
int length = + audiopack.size;
sample_index = (audioCodecCtx->extradata[] & 0x07) << ;
temp = (audioCodecCtx->extradata[]&0x80);
switch(audioCodecCtx->sample_rate)
{
case :
{
sample_index = 0x7;
}break;
default:
{
sample_index = sample_index + (temp>>);
}break;
}
channel = ((audioCodecCtx->extradata[] - temp) & 0xff) >> ;
bits[] = 0xff;
bits[] = 0xf1;
bits[] = 0x40 | (sample_index<<) | (channel>>);
bits[] = ((channel&0x3)<<) | (length >>);
bits[] = (length>>) & 0xff;
bits[] = ((length<<) & 0xff) | 0x1f;
bits[] = 0xfc; fwrite(bits,,,f);
结果失败了,添加这几个自己的adts头还是一样解码不出数据。
最后参考http://blog.itpub.net/30168498/viewspace-1576794/这个文章的代码,进行应用,顺利解码aac。
(原)从mp4,flv文件中解析出h264和aac,送解码器解码失败的更多相关文章
- js中解析json对象:JSON.parse()用于从一个字符串中解析出json对象, JSON.stringify()用于从一个对象解析出字符串。
JSON.parse()用于从一个字符串中解析出json对象. var str = '{"name":"huangxiaojian","age&quo ...
- atitit.mp4 视频文件多媒体格式结构详解
atitit.mp4 视频文件多媒体格式结构详解 1. 一.基本概念1 2. MP4文件概述2 3. mp4是由一个个“box”组成的,2 4. 典型简化mp43 5. Fragments5 6. r ...
- 嵌入式 H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流
一.MP4格式基本概念 MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二.MP4封装格式核心概念 1 MP4封装格式对应标准为 ISO/IEC 14496-12(信息技术 视听对象 ...
- [转]【流媒體】H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流
[流媒體]H264—MP4格式及在MP4文件中提取H264的SPS.PPS及码流 SkySeraph Apr 1st 2012 Email:skyseraph00@163.com 一.MP4格式基本 ...
- 多媒体开发之---H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流
一.MP4格式基本概念 MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二.MP4封装格式核心概念 1 MP4封装格式对应标准为 ISO/IEC 14496-12(信息技术 视听对象 ...
- 【转】打包AAC码流到FLV文件
AAC编码后数据打包到FLV很简单.1. FLV音频Tag格式 字节位置 意义0x08, ...
- flv格式详解+实例剖析
简介 FLV(Flash Video)是现在非常流行的流媒体格式,由于其视频文件体积轻巧.封装播放简单等特点,使其很适合在网络上进行应用,目前主流的视频网站无一例外地使用了FLV格式.另外由于当前浏览 ...
- FLV格式详解
Overview Flash Video(简称FLV),是一种流行的网络格式.目前国内外大部分视频分享网站都是采用的这种格式. File Structure 从整个文件上开看,FLV是由The FLV ...
- .Net类库 压缩文件 与 Ionic.Zip 批量压缩不同目录文件与解压 文件
using System; using System.IO; using System.IO.Compression; using System.Linq; using System.Text; us ...
随机推荐
- [Windows Azure] How to use the Windows Azure Blob Storage Service in .NET
How to use the Windows Azure Blob Storage Service in .NET version 1.7 version 2.0 This guide will de ...
- shell(7):四则运算
shell 四则运算:expr,let,bc,(()), 1.expr的用法: expr命令是一个手工命令行计数器,用于在UNIX/LINUX下求表达式变量的值,一般用于整数值,也可用于字符串. 详细 ...
- 【内核】嵌入式linux内核的五个子系统
Perface Linux内核主要由进程调度(SCHED).内存管理(MM).虚拟文件系统(VFS).网络接口(NET)和进程间通信(IPC)5个子系统组成,如图1所示. 图1 Linux内核的组成部 ...
- git stash 暂存恢复和文件误删恢复
git commit提交文件,服务器返回本地文件有修改. 1.git stash :暂存本地代码 2.git pull origin develop : 获取远程分支代码 3.git stash po ...
- Joint Extraction of Entities and Relations论文解析
1. 前言 实体和关系的联合抽取问题作为信息抽取的关键任务,其实现方法可以简单分为两类: 一类是串联抽取方法.传统的串联抽取就是首先进行实体抽取,然后进行关系识别.这种分开的方法比较容易实现,而且各个 ...
- 基于jQuery个性圆圈倒计时特效
基于jQuery个性圆圈倒计时特效里面包含十几款不用效果的jQuery倒计时特效下载.效果图如下: 在线预览 源码下载 实现的代码. html代码: <section class=" ...
- 11月Android笔记
不知不觉又过了两个月了,过的够呛.新收获:百度云,视频直播,sqlite加密,lucene,SlidingPaneLayout. 我发现只要你有心,你期望的事情会接踵而来(不包括爱情= =) 上个游戏 ...
- 【Unity】自定义编辑器窗口——拓展编辑器功能
最近学习了Unity自定义编辑器窗口,下面简单总结,方便用到时回顾. 新建一个脚本: using UnityEngine; using System.Collections; using UnityE ...
- Linux下用文件IO的方式操作GPIO(/sys/class/gpio)
通过sysfs方式控制GPIO,先访问/sys/class/gpio目录,向export文件写入GPIO编号,使得该GPIO的操作接口从内核空间暴露到用户空间,GPIO的操作接口包括direction ...
- SpringMVC REST 风格静态资源访问配置
1 在web.xml中使用默认servlet处理静态资源,缺点是如果静态资源过多,则配置量会比较大,一旦有遗漏,则会造成资源无法正常显示或404错误. <!-- 静态资源访问控制 --> ...