使用 libavcodec 的 mpegts 容器中的原始 H264 帧

2024-03-31

我非常感谢对以下问题的帮助:

我有一个带摄像头的小工具,可以生成 H264 压缩视频帧,这些帧将发送到我的应用程序。这些帧不在容器中,只是原始数据。

我想用ffmpeg和libav函数创建一个视频文件,方便以后使用。

如果我解码帧,然后对其进行编码,一切正常,我会得到一个有效的视频文件。 (解码/编码步骤是通常的libav命令,这里没什么花哨的,我从万能的互联网上获取它们,它们坚如磐石)...但是,我在解码和编码上浪费了很多时间,所以我想跳过这一步,直接将帧放入输出流中。现在,问题来了。

这是我想出的用于生成编码的代码:

AVFrame* picture;

avpicture_fill((AVPicture*) picture, (uint8_t*)frameData, 
                 codecContext->pix_fmt, codecContext->width,
                 codecContext->height);
int outSize = avcodec_encode_video(codecContext, videoOutBuf, 
                 sizeof(videoOutBuf), picture);
if (outSize > 0) 
{
    AVPacket packet;
    av_init_packet(&packet);
    packet.pts = av_rescale_q(codecContext->coded_frame->pts,
                  codecContext->time_base, videoStream->time_base);
    if (codecContext->coded_frame->key_frame) 
    {
        packet.flags |= PKT_FLAG_KEY;
    }
    packet.stream_index = videoStream->index;
    packet.data =  videoOutBuf;
    packet.size =  outSize;

    av_interleaved_write_frame(context, &packet);
    put_flush_packet(context->pb);
}

其中变量如下:

frameData是来自相机的解码帧数据,它在上一步中被解码并且videoOutBuf是一个用于保存数据的普通 uint8_t 缓冲区

我修改了应用程序,以便不解码帧,而只是传递数据,例如:

    AVPacket packet;
    av_init_packet(&packet);

    packet.stream_index = videoStream->index;
    packet.data = (uint8_t*)frameData;
    packet.size = currentFrameSize;

    av_interleaved_write_frame(context, &packet);
    put_flush_packet(context->pb);

where

frameData是原始的 H264 帧 和currentFrameSize是原始 H264 帧的大小,即我从设备获得的每一帧的字节数。

突然间,应用程序不再正常工作,生成的视频无法播放。这是显而易见的,因为我没有为数据包设置正确的 PTS。我所做的是以下(我很绝望,你可以从这个方法中看到它:))

    packet.pts = timestamps[timestamp_counter ++];

where timestamps实际上是由上面的工作代码生成的 PTS 列表,并写入文件(是的,您没有看错,我记录了 10 分钟会话的所有 PTS,并且想要使用它们)。

该应用程序仍然无法运行。

现在,我不知道该怎么办,所以问题是:

我想使用 libav 函数创建一个“mpegts”视频流,在流中插入已经编码的视频帧并用它创建一个视频文件。我该怎么做?

谢谢, F。


我相信如果你设置以下内容,你就会看到视频播放。

packet.flags |= AV_PKT_FLAG_KEY;
packet.pts = packet.dts = 0;

您确实应该根据 h264 数据包标头设置 packet.flags。你可以尝试这个家伙堆栈溢出了 https://stackoverflow.com/q/1957427建议直接从流中提取。

如果您还添加音频,那么 pts/dts 将更加重要。我建议你学习本教程 http://dranger.com/ffmpeg/tutorial05.html

EDIT

我抽出时间从我的测试应用程序中提取出对我有用的内容。由于某种原因,dts/pts 值为零对我有用,但 0 或 AV_NOPTS_VALUE 以外的值则不起作用。我想知道我们是否有不同版本的 ffmpeg。我有最新的git://git.videolan.org/ffmpeg.git.

fftest.cpp

#include <string>

#ifndef INT64_C
#define INT64_C(c) (c ## LL)
#define UINT64_C(c) (c ## ULL)
#endif

//#define _M
#define _M printf( "%s(%d) : MARKER\n", __FILE__, __LINE__ )

extern "C"
{
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
};


AVFormatContext *fc = 0;
int vi = -1, waitkey = 1;

// < 0 = error
// 0 = I-Frame
// 1 = P-Frame
// 2 = B-Frame
// 3 = S-Frame
int getVopType( const void *p, int len )
{   
    if ( !p || 6 >= len )
        return -1;

    unsigned char *b = (unsigned char*)p;

    // Verify NAL marker
    if ( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] )
    {   b++;
        if ( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] )
            return -1;
    } // end if

    b += 3;

    // Verify VOP id
    if ( 0xb6 == *b )
    {   b++;
        return ( *b & 0xc0 ) >> 6;
    } // end if

    switch( *b )
    {   case 0x65 : return 0;
        case 0x61 : return 1;
        case 0x01 : return 2;
    } // end switch

    return -1;
}

void write_frame( const void* p, int len )
{
    if ( 0 > vi )
        return;

    AVStream *pst = fc->streams[ vi ];

    // Init packet
    AVPacket pkt;
    av_init_packet( &pkt );
    pkt.flags |= ( 0 >= getVopType( p, len ) ) ? AV_PKT_FLAG_KEY : 0;   
    pkt.stream_index = pst->index;
    pkt.data = (uint8_t*)p;
    pkt.size = len;

    // Wait for key frame
    if ( waitkey )
        if ( 0 == ( pkt.flags & AV_PKT_FLAG_KEY ) )
            return;
        else
            waitkey = 0;

    pkt.dts = AV_NOPTS_VALUE;
    pkt.pts = AV_NOPTS_VALUE;

//  av_write_frame( fc, &pkt );
    av_interleaved_write_frame( fc, &pkt );
}

void destroy()
{
    waitkey = 1;
    vi = -1;

    if ( !fc )
        return;

_M; av_write_trailer( fc );

    if ( fc->oformat && !( fc->oformat->flags & AVFMT_NOFILE ) && fc->pb )
        avio_close( fc->pb ); 

    // Free the stream
_M; av_free( fc );

    fc = 0;
_M; 
}

int get_nal_type( void *p, int len )
{
    if ( !p || 5 >= len )
        return -1;

    unsigned char *b = (unsigned char*)p;

    // Verify NAL marker
    if ( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] )
    {   b++;
        if ( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] )
            return -1;
    } // end if

    b += 3;

    return *b;
}

int create( void *p, int len )
{
    if ( 0x67 != get_nal_type( p, len ) )
        return -1;

    destroy();

    const char *file = "test.avi";
    CodecID codec_id = CODEC_ID_H264;
//  CodecID codec_id = CODEC_ID_MPEG4;
    int br = 1000000;
    int w = 480;
    int h = 354;
    int fps = 15;

    // Create container
_M; AVOutputFormat *of = av_guess_format( 0, file, 0 );
    fc = avformat_alloc_context();
    fc->oformat = of;
    strcpy( fc->filename, file );

    // Add video stream
_M; AVStream *pst = av_new_stream( fc, 0 );
    vi = pst->index;

    AVCodecContext *pcc = pst->codec;
_M; avcodec_get_context_defaults2( pcc, AVMEDIA_TYPE_VIDEO );
    pcc->codec_type = AVMEDIA_TYPE_VIDEO;

    pcc->codec_id = codec_id;
    pcc->bit_rate = br;
    pcc->width = w;
    pcc->height = h;
    pcc->time_base.num = 1;
    pcc->time_base.den = fps;

    // Init container
_M; av_set_parameters( fc, 0 );

    if ( !( fc->oformat->flags & AVFMT_NOFILE ) )
        avio_open( &fc->pb, fc->filename, URL_WRONLY );

_M; av_write_header( fc );

_M; return 1;
}

int main( int argc, char** argv )
{
    int f = 0, sz = 0;
    char fname[ 256 ] = { 0 };
    char buf[ 128 * 1024 ];

    av_log_set_level( AV_LOG_ERROR );
    av_register_all();

    do
    {
        // Raw frames in v0.raw, v1.raw, v2.raw, ...
//      sprintf( fname, "rawvideo/v%lu.raw", f++ );
        sprintf( fname, "frames/frame%lu.bin", f++ );
        printf( "%s\n", fname );

        FILE *fd = fopen( fname, "rb" );
        if ( !fd )
            sz = 0;
        else
        {
            sz = fread( buf, 1, sizeof( buf ) - FF_INPUT_BUFFER_PADDING_SIZE, fd );
            if ( 0 < sz )
            {
                memset( &buf[ sz ], 0, FF_INPUT_BUFFER_PADDING_SIZE );          

                if ( !fc )
                    create( buf, sz );

                if ( fc )
                    write_frame( buf, sz );

            } // end if

            fclose( fd );

        } // end else

    } while ( 0 < sz );

    destroy();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 libavcodec 的 mpegts 容器中的原始 H264 帧 的相关文章

  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 用于检查类是否具有运算符/成员的 C++ 类型特征[重复]

    这个问题在这里已经有答案了 可能的重复 是否可以编写一个 C 模板来检查函数是否存在 https stackoverflow com questions 257288 is it possible to write a c template
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • BitTorrent 追踪器宣布问题

    我花了一点业余时间编写 BitTorrent 客户端 主要是出于好奇 但部分是出于提高我的 C 技能的愿望 我一直在使用理论维基 http wiki theory org BitTorrentSpecification作为我的向导 我已经建
  • Clang 3.1 + libc++ 编译错误

    我已经构建并安装了 在前缀下 alt LLVM Clang trunk 2012 年 4 月 23 日 在 Ubuntu 12 04 上成功使用 GCC 4 6 然后使用此 Clang 构建的 libc 当我想使用它时我必须同时提供 lc
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • 对现有视频添加水印

    我正在寻找一种用 C 在视频上加水印的方法 就像在上面写文字一样 图片或文字标签 我该怎么做 谢谢 您可以使用 Nreco 视频转换器 代码看起来像 NReco VideoConverter FFMpegConverter wrap new
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 混合 ExecutionContext.SuppressFlow 和任务时 AsyncLocal.Value 出现意外值

    在应用程序中 由于 AsyncLocal 的错误 意外值 我遇到了奇怪的行为 尽管我抑制了执行上下文的流程 但 AsyncLocal Value 属性有时不会在新生成的任务的执行范围内重置 下面我创建了一个最小的可重现示例来演示该问题 pr
  • 是否可以在 .NET Core 中将 gRPC 与 HTTP/1.1 结合使用?

    我有两个网络服务 gRPC 客户端和 gRPC 服务器 服务器是用 NET Core编写的 然而 客户端是托管在 IIS 8 5 上的 NET Framework 4 7 2 Web 应用程序 所以它只支持HTTP 1 1 https le
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定
  • 如何将服务器服务连接到 Dynamics Online

    我正在修改内部管理应用程序以连接到我们的在线托管 Dynamics 2016 实例 根据一些在线教程 我一直在使用OrganizationServiceProxy out of Microsoft Xrm Sdk Client来自 SDK
  • 如何在文本框中插入图像

    有没有办法在文本框中插入图像 我正在开发一个聊天应用程序 我想用图标图像更改值 等 但我找不到如何在文本框中插入图像 Thanks 如果您使用 RichTextBox 进行聊天 请查看Paste http msdn microsoft co

随机推荐

  • 列出特定 AMI 的所有可能的实例类型?

    我知道以前曾有人问过这个问题 但我尚未找到用于获取给定 Amazon AMI 的可能实例类型列表的解决方法或解决方案 我正在使用 NET SDK 有没有人能够找到一种方法来做到这一点 这不可能 AMI 只是磁盘的映像 AWS 通常 可以检测
  • C#,“未将对象引用设置为对象的实例。”错误

    我有这个代码 namespace YellowBox public partial class Form1 Form private string sid FileTransferManager fm new FileTransferMan
  • UpsetR 更改图表中的集名称标签

    我正在尝试将 UpsetR 图中的集合名称标签 使用 Upset 函数 更改为多个单词的字符串 我希望将集合标签显示为 A 描述 B 描述 C 描述 而不是 A B C 作为集合标签 我不想在单词之间使用句号或下划线 test lt ups
  • 有没有办法在 PHP4 中模拟 PHP5 的 __call() 魔术方法?

    PHP5有一个 神奇的方法 call 可以在调用未定义方法时调用的任何类上定义 它大致相当于 Ruby 的method missing或者 Perl 的AUTOLOAD 在旧版本的 PHP 中可以做这样的事情吗 我缺少的最重要的一点是 ca
  • 修复未加引号的 PHP 数组键

    或者更确切地说 修复用作 PHP 数组键的未加引号的字符串 但这对于标题来说有点长 我继承了一个相当大的代码库 其中数组的编写方式如下 array id 0 array value test 虽然这段代码实际上有效 但它抛出了很多Use o
  • 计算 3D(或 n 维)质心的最佳方法是什么?

    作为工作项目的一部分 我必须计算 3D 空间中一组点的质心 现在我正在以一种看似简单但天真的方式来做这件事 通过取每组点的平均值 如下所示 centroid average x average y average z where x y a
  • 科学记数法 android java

    我用java为android编写了一个简单的计算器 我使用 double 作为变量 它给我的结果在达到一定数量的小数后以科学计数法表示 尽管仍然有足够的小数空间 有没有什么简单的方法可以将科学符号转换为 正常 符号 我现在可以分别用一个按钮
  • 如何查看node.js发送到服务器的请求?

    关于这个问题 在 Nodejs Protractor 中将 Cookie 从一个请求传输 传递到另一个请求 https stackoverflow com questions 42078780 transfer pass cookies f
  • PHP 中的标头会覆盖 HTTP 响应代码

    在 Apache 级别解决设置规则时 发现 php 中的 header Location filename php 覆盖了响应代码 看下面的代码 Expected result HTTP 1 1 308 永久重定向 主机 本地主机 8000
  • 如何显示 SVG 文件中的所有符号?

    我有一个 SVG 文件 如下所示
  • 将数据库初始化调用放入 C# 构造函数中可以吗? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我见过这是各种代码库 并且想知道这是否普遍不受欢迎 例如 public class MyClass public int Id public M
  • 为什么我必须在 Fortran 中隐式指定函数的双精度返回值?

    我是 Fortran 新手 我正在尝试common堵塞 我的代码很简单 program main implicit double precision p real 8 x y common yvalue y x 3d0 y 3d0 prin
  • 使用 MongoDB 的 MapReduce 选择不同的多个字段

    我想在 MongoDB 上执行这个 SQL 语句 SELECT DISTINCT book author from library 到目前为止 MongoDB 的 DISTINCT 一次仅支持一个字段 对于多个字段 我们必须使用 GROUP
  • 具有多种模式的 Python Regex Sub

    我正在尝试使用正则表达式子分组来匹配多个模式 并将匹配替换为与下面的字符串具有类似格式的数据文件的星号 然而 我只得到了第一场比赛所需的结果 随后的匹配正在消耗我没想到的字符串 有没有更好的方法来获得下面所需的输出 import re my
  • Knockoutjs 自定义绑定在项目完全渲染之前执行

    我正在尝试对项目列表执行回调以使用数据表 http datatables net 现在我想在渲染所有项目之后执行回调 而不是在渲染每个项目之后执行回调 跟随那个所以问题 https stackoverflow com questions 1
  • 如何在 Grails 中使用嵌入的 GORM 类?

    继GORM 文档 http grails org doc 2 2 0 guide GORM html gormComposition我尝试在 Grails 2 2 1 中使用以下域类 package grailscompositiontes
  • 如何在我的 React Native Android 应用程序中使用 Crashlytics?

    我正在尝试弄清楚如何在我的 React Native Android 应用程序中使用 Fabric 的 Crashlytics 我按照 Fabric 主页上的步骤操作 并在 build gradle 文件中添加了一些行 但构建总是崩溃 使用
  • Select_lated() 向后关系 - 自动模型总体

    如果我有以下模型 class Contact models Model name models CharField max length 100 class ContactAddress models Model line1 models
  • 如何以编程方式使用 NSTextFinder?

    我想在一个中进行 查找 操作NSTextView不使用内置查找栏 如何以编程方式设置搜索字符串并在文本视图中突出显示结果 这适用于 macOS 10 12 及更高版本 FWIW 这不是这个问题的重复 NSTextField 以编程方式设置搜
  • 使用 libavcodec 的 mpegts 容器中的原始 H264 帧

    我非常感谢对以下问题的帮助 我有一个带摄像头的小工具 可以生成 H264 压缩视频帧 这些帧将发送到我的应用程序 这些帧不在容器中 只是原始数据 我想用ffmpeg和libav函数创建一个视频文件 方便以后使用 如果我解码帧 然后对其进行编