从MPEG-2传输流(H.264-附件B)字节流中提取原始I帧图像数据

问题描述 投票:2回答:2

上下文

我正在尝试使用H.264附件B编解码器从MPEG-2传输流中提取每个I帧的原始图像数据。该视频每2秒间隔包含I帧。我已经读到可以在类型为5的NALu起始代码之后找到I帧(例如IDR图片的编码切片)。这些NALu的字节有效载荷包含构成一个完整帧的所有必要数据。以我的理解,尽管是H.264编码格式。

我想通过找到包含I帧的NALu,保存有效载荷并将有效载荷解码为某种普遍存在的原始图像格式以访问像素数据等,来从传入的字节流中提取这些I帧的解决方案。] >

注意:如果可能,我想避免使用像ffmpeg

这样的文件系统依赖二进制文件,如果可行,更重要的是!

PoC

到目前为止,我已经在锈中建立了一个PoC来查找字节偏移和I帧的字节大小:

use std::fs::File;
use std::io::{prelude::*, BufReader};
extern crate image;

fn main() {
    let file = File::open("vodpart-0.ts").unwrap();
    let reader = BufReader::new(file);

    let mut idr_payload = Vec::<u8>::new();
    let mut total_idr_frame_count = 0;
    let mut is_idr_payload = false;
    let mut is_nalu_type_code = false;
    let mut start_code_vec = Vec::<u8>::new();

    for (pos, byte_result) in reader.bytes().enumerate() {
        let byte = byte_result.unwrap();
        if is_nalu_type_code {
            is_idr_payload = false;
            is_nalu_type_code = false;
            start_code_vec.clear();
            if byte == 101 {
                is_idr_payload = true;
                total_idr_frame_count += 1;
                println!("Found IDR picture at byte offset {}", pos);
            }
            continue;
        }
        if is_idr_payload {
            idr_payload.push(byte);
        }
        if byte == 0 {
            start_code_vec.push(byte);
            continue;
        }
        if byte == 1 && start_code_vec.len() >= 2 {
            if is_idr_payload {
                let payload = idr_payload.len() - start_code_vec.len() + 1;
                println!("Previous NALu payload is {} bytes long\n", payload);
                save_image(&idr_payload.as_slice(), total_idr_frame_count);
                idr_payload.clear();
            }
            is_nalu_type_code = true;
            continue;
        }
        start_code_vec.clear();
    }

    println!();
    println!("total i frame count: {}", total_idr_frame_count);

    println!();
    println!("done!");
}

fn save_image(buffer: &[u8], index: u16) {
    let image_name = format!("image-{}.jpg", index);
    image::save_buffer(image_name, buffer, 858, 480, image::ColorType::Rgb8).unwrap()
}

其结果如下:

Found IDR picture at byte offset 870
Previous NALu payload is 202929 bytes long

Found IDR picture at byte offset 1699826
Previous NALu payload is 185069 bytes long

Found IDR picture at byte offset 3268686
Previous NALu payload is 145218 bytes long

Found IDR picture at byte offset 4898270
Previous NALu payload is 106114 bytes long

Found IDR picture at byte offset 6482358
Previous NALu payload is 185638 bytes long


total i frame count: 5

done!

这是正确的,根据我对H.264比特流查看器等的研究,在这些字节偏移处肯定有5个I帧!

问题是,我不了解如何从H.264字节流有效负载转换为原始图像RBG数据格式。最终转换为jpg的图像只是一个模糊的烂摊子,约占图像区域的10%。

例如:

Ouput jpg image

问题
  1. 是否需要执行解码步骤?

  • 我是否正确地解决了这个问题,是否可以尝试尝试自己,还是应该依靠另一个库?
  • 任何帮助将不胜感激!

    上下文,我正在尝试从具有H.264附件B编解码器的MPEG-2传输流中提取每个I帧的原始图像数据。该视频每2秒间隔包含I帧。我读过...

    image rust frame h.264 mpeg
    2个回答
    0
    投票

    这些是您提出的相当开放的问题。我将概述从MPEG-2传输流到H.264附件B的操作。然后您可以形成自己的意见:


    0
    投票

    “是否需要执行解码步骤?”

    © www.soinside.com 2019 - 2024. All rights reserved.