我正在研究一个转换器,它将H.264 / AAC RTMP流转换为有效的MP4文件。我已经 大部分 完成了。我正在解析AMF标签,读取AVCDecoderConfigurationRecord和AACSpecificConfig,正在生成有效的moov原子,等等。
在发现并修复代码中的一些错误之后,我得到了一个 主要是 有效的MP4文件。但是,当我尝试阅读ffprobe
中的视频时,出现以下错误:
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f9fb4000b80] Failed to open codec in avformat_find_stream_info
Last message repeated 1 times
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f9fb4000b80] Could not find codec parameters for stream 1 (Video: h264 (avc1 / 0x31637661), none, 640x360): unspecified pixel format
Consider increasing the value for the 'analyzeduration' and 'probesize' options
找不到像素格式。浏览我的AVCDecoderConfigurationRecord解析逻辑(该逻辑用来生成avcC
原子,作为avc1
原子的一部分),我有以下内容:
// Parsed per: https://github.com/LiminWang/simple-rtmp-server/blob/master/trunk/doc/H.264-AVC-ISO_IEC_14496-15.pdf
var info = parseAVCConfig(packet);
// Fortunately my video sample has one of each of these
// I may need to concatenate multiple in the future
var sps = info.sps[0];
var pps = info.pps[0];
var avcc = box(
types.avcC,
new Uint8Array([
// Version
0x01,
// Profile
info.profile,
// Profile Compat
info.compat,
// Level
info.level,
// LengthSizeMinusOne, hard-coded to 4 bytes (copied HLS.js)
0xfc | 3,
// 3bit reserved (111) + numOfSequenceParameterSets
0xE0 | sps.byteLength
]
.concat(Array.from(sps))
.concat([
// NumOfPictureParametersets
pps.byteLength
])
.concat(Array.from(pps))
)
);
您可以看到avcc
原子包含配置文件,兼容性和级别-但是之后,我只是直接从AVCDecoderConfigurationRecord复制了SPS和PPS。我在原子中的任何地方都没有定义像素格式,因此我假设它是SPS或PPS的一部分。
查看AVCDecoderConfigurationRecord的规范,没有专门称为“像素格式”的内容,但是有“ chroma_format”,“ bit_depth_luma_minus8”和“ bit_depth_chroma_minus_8”-但是,只有在配置文件为100、110, 122或244。我的个人资料是66(这些字节对我来说不存在)
目前,我正在做的概念证明仅支持单个视频,因此在最坏的情况下,我可以将像素格式硬编码为yuv420
。但我什至不知道将这些信息放在输出MP4中的位置。它是否进入avcC
原子中?还是avc1
原子?还是mvhd
原子?
链接:
ffprobe
说找不到像素格式。 http://files.stevendesu.com/buffer.mp4 ffmpeg
转换为MP4进行比较。 http://files.stevendesu.com/test.mp4 答案 0 :(得分:0)
看看chroma_format_idc
建议书。 ITU-T H.264建议书(04/2017)-7.3.2.1.1序列参数集数据语法。 chroma_format_idc
是SPS的一部分。
对于profile_idc
,将chroma_format_idc
存储在SPS内,例如chroma_format_idc specifies the chroma sampling relative to the luma sampling as specified in clause 6.2. The value of
chroma_format_idc shall be in the range of 0 to 3, inclusive. When chroma_format_idc is not present, it shall be inferred
to be equal to 1 (4:2:0 chroma format).
100、110、122、244、44、83、86、118、128、138、139、134或135。否则,您假设为1(= 4:2:0)。
7.4.2.1.1序列参数集数据语义
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class LevelActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_level);
Button btn1 = (Button) findViewById(R.id.button1);
Button btn2 = (Button) findViewById(R.id.button2);
Button btn3 = (Button) findViewById(R.id.button3);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int seconds = 120;
// int Live = 10;
Intent myIntent = new Intent(LevelActivity.this, GameActivity.class);
myIntent.putExtra("secondA", seconds);
startActivity(myIntent);
// myIntent.putExtra("varLive", Live);
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int seconds = 60;
// int Live = 10;
Intent myIntent = new Intent(LevelActivity.this, GameActivity.class);
myIntent.putExtra("secondA", seconds);
startActivity(myIntent);
// myIntent.putExtra("varLive", Live);
}
});
btn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int seconds = 40;
// int Live = 10;
Intent myIntent = new Intent(LevelActivity.this, GameActivity.class);
myIntent.putExtra("secondA", seconds);
startActivity(myIntent);
// myIntent.putExtra("varLive", Live);
}
});
}
}