H.264 MP4文件中的像素格式存储在哪里?

时间:2018-12-12 14:42:19

标签: mp4 h.264

我正在研究一个转换器,它将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原子?

链接:

1 个答案:

答案 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);
        }
    });
}
}