使用FFmpeg开发2-比特流过滤器

news/2025/2/12 21:03:29/

        在使用FFmpeg处理视频文件时,会遇到需要提取视频流的情况。例如有一个H264编码的mp4文件,需要提取帧数据送到解码器解码,这时候过滤器就派上用场了。

        为什么要这么干,因为我用的是自有的硬件解码器,还未集成到FFmpeg中,没法在FFmpeg中直接调用。

        对于H264裸流文件,一般使用的AnnexB格式,每一帧由NAL单元加上一个起始码组成(三字节00 00 01或者四字节00 00 00 01)。解码器就是根据这个头来分割数据的。

  

        在mp4(H264编码)文件中,一般使用的是AVVC格式,因为封装了同步信息,就去掉了上述的起始码,如果见数据直接丢到解码器,解码器是没法找到数据头进行解码的,因此需要过滤器来为数据加上这个起始码。h264_mp4toannexb码流过滤器就解决了这个问题。它识别文件头,并提取里面的extradata,extradata这个数据就是封装信息。然后给每个NAL单元添加上起始码,再把数据送到硬件解码器。

        对于mp4(H265编码)文件,则使用hevc_mp4toannexb。

        在wrap的使用博文中介绍了裸流解码,这时候如果搭配了FFmpeg的过滤器,即可以实现读取mp4文件,通过过滤器分离出裸H264数据,然后送到解码器解码,实现对封装数据的解码。

imx VPU解码分析3-wrap的示例-CSDN博客

        这里给出一个实现参考,从imx的hantro中抠出来的,从中也可以一窥用法,支持的FFmpeg版本比较旧,有时间再整理下新版的代码。貌似新版的FFmpeg将过滤器集成到了读入视频的过程,不需要额外处理了。

/*------------------------------------------------------------------------------
--       Copyright (c) 2015-2017, VeriSilicon Inc. All rights reserved        --
--         Copyright (c) 2011-2014, Google Inc. All rights reserved.          --
--         Copyright (c) 2007-2010, Hantro OY. All rights reserved.           --
--                                                                            --
-- This software is confidential and proprietary and may be used only as      --
--   expressly authorized by VeriSilicon in a written licensing agreement.    --
--                                                                            --
--         This entire notice must be reproduced on all copies                --
--                       and may not be removed.                              --
--                                                                            --
--------------------------------------------------------------------------------
-- Redistribution and use in source and binary forms, with or without         --
-- modification, are permitted provided that the following conditions are met:--
--   * Redistributions of source code must retain the above copyright notice, --
--       this list of conditions and the following disclaimer.                --
--   * Redistributions in binary form must reproduce the above copyright      --
--       notice, this list of conditions and the following disclaimer in the  --
--       documentation and/or other materials provided with the distribution. --
--   * Neither the names of Google nor the names of its contributors may be   --
--       used to endorse or promote products derived from this software       --
--       without specific prior written permission.                           --
--------------------------------------------------------------------------------
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"--
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  --
-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE --
-- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE  --
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR        --
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF       --
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS   --
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN    --
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)    --
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --
-- POSSIBILITY OF SUCH DAMAGE.                                                --
--------------------------------------------------------------------------------
------------------------------------------------------------------------------*/#include "libav-wrapper.h"#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavcodec/bsf.h"
#include "libavutil/mem.h"#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>static AVFormatContext *p_format_ctx = NULL;
static AVCodecContext *p_codec_ctx = NULL;
static AVCodecParameters *origin_par = NULL;
//gan 20230907 AVBitStreamFilterContext is instand by AVBSFContext
//static AVBitStreamFilterContext *bsfc = NULL;
static AVBSFContext *bsfc = NULL;static int video_stream = -1;
static int raw_h264 = 0;uint8_t *byte_buffer = NULL;
int byte_buffer_size = 0;
static int num;
void libav_init() {//av_register_all();//av_log(NULL, AV_LOG_INFO, "Using %s\nConfig: %s\n\n", LIBAVCODEC_IDENT,//       avcodec_configuration());
}void libav_release() {if (bsfc)//av_bitstream_filter_close(bsfc);av_bsf_free(bsfc);if (p_format_ctx)avformat_close_input(&p_format_ctx);
}int libav_open(const char *fname) {printf("libav_open\n");num = 1;/* Open video file */if (avformat_open_input(&p_format_ctx, fname, NULL, NULL) != 0) {av_log(NULL, AV_LOG_ERROR, "Couldn't open file!\n");return -1;}/* Retrieve stream information */if (avformat_find_stream_info(p_format_ctx, NULL) < 0) {/* this is not fatal error, yet */av_log(NULL, AV_LOG_ERROR, "Couldn't find stream information!\n");}/* Dump information about file onto standard error */av_dump_format(p_format_ctx, 0, fname, 0);/* Find the video stream */video_stream = av_find_best_stream(p_format_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);if (video_stream < 0) {av_log(NULL, AV_LOG_ERROR, "Didn't find a video stream!\n");return -1;}origin_par = p_format_ctx->streams[video_stream]->codecpar;/* Get a pointer to the codec context for the video stream *///p_codec_ctx = p_format_ctx->streams[video_stream]->codec;p_codec_ctx = avcodec_alloc_context3(avcodec_find_decoder(origin_par->codec_id));  avcodec_parameters_to_context(p_codec_ctx, origin_par); printf("p_format_ctx->iformat->long_name,%s\n", p_format_ctx->iformat->long_name);if (!av_strcasecmp(p_format_ctx->iformat->long_name, "raw H.264 video")) {raw_h264 = 1;printf("raw_h264\n");} else {/* have to use a filter to get the byte stream out *///bsfc = av_bitstream_filter_init("h264_mp4toannexb");printf("not h264,have to filter\n");const AVBitStreamFilter *pfilter = av_bsf_get_by_name("h264_mp4toannexb");av_bsf_alloc(pfilter, &bsfc);if (!bsfc) {av_log(p_codec_ctx, AV_LOG_ERROR,"Couldn't open the h264_mp4toannexb BSF!\n");return -1;}}//byte_buffer_size = av_image_get_buffer_size(p_codec_ctx->pix_fmt, p_codec_ctx->width, p_codec_ctx->height, 16);//byte_buffer = av_malloc(byte_buffer_size);//printf("**byte_buffer_size=%d\n", byte_buffer_size);return 0;
}//return -1 ,over;0, not video;other, ok 
int libav_read_frame(char *buffer) {//printf("libav_read_frame\n");int ret;uint8_t *frame_data = NULL;  // Initialize to NULLAVPacket *pkt = av_packet_alloc();pkt->data = NULL;pkt->size = 0;ret = av_read_frame(p_format_ctx, pkt);//read overif (ret != 0) {return 0;}for(int i=0;i<pkt->size;i++)printf("%2d ", *(pkt->data+i));if(ret == 0 && pkt->stream_index == video_stream){printf("av_read_frame, num=%d, pkt->size=%d\n", num++, pkt->size);if (!raw_h264) {uint8_t *orig_extradata = NULL;int orig_extradata_size = 0;orig_extradata_size = p_codec_ctx->extradata_size;orig_extradata = av_mallocz(orig_extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);memcpy(orig_extradata, p_codec_ctx->extradata, orig_extradata_size);//ret = av_bitstream_filter_filter(bsfc, p_codec_ctx, NULL, &frame_data, &frame_size, pkt->data, pkt->size, 0);av_bsf_send_packet(bsfc, pkt);printf("av_read_frame, 1, pkt->size=%d\n", pkt->size);ret = av_bsf_receive_packet(bsfc, pkt);printf("av_read_frame, 2, pkt->size=%d\n", pkt->size);for(int i=0;i<pkt->size;i++)printf("%2d ", *(pkt->data+i));if (p_codec_ctx->extradata == NULL) {p_codec_ctx->extradata = orig_extradata;p_codec_ctx->extradata_size = orig_extradata_size;} else {av_free(orig_extradata);}av_bsf_free(&bsfc);}memcpy(buffer, pkt->data, pkt->size);return pkt->size;}else{printf("av_read_frame, no video\n");return 0;}
}

从中可以看出主要是 这二个函数:

av_bsf_send_packet(bsfc, pkt);
av_bsf_receive_packet(bsfc, pkt);

av_bitstream_filter_filter函数已经被废弃。

在4.2版本上改改测试了下,是可行的。后期再试试新版。

如果不想使用FFmepg来读取H264裸流文件,可以参考这篇博文,使用纯C简单实现。

纯C读取文件实现解析H264裸流每一帧数据-CSDN博客


http://www.ppmy.cn/news/1254639.html

相关文章

5G承载网和大客户承载的演进

文章目录 移动4/5G承载网联通和电信4/5G承载网M-OTN&#xff08;Metro-optimized OTN&#xff09;&#xff0c;城域型光传送网PeOTN&#xff08;packet enhanced optical transport network&#xff09;&#xff0c;分组增强型OTN板卡增强型PeOTN集中交叉型PeOTN VC-OTN&#x…

npm ERR! notarget No matching version found for @eslint/eslintrc@^2.1.4.

文章目录 Intro解决流程总结前置信息了解npm 镜像源三个要用到的npm命令 官方源确认查看当前镜像源的详情解决&#xff1a; 切换镜像源后重试重新操作 事后感受 Intro 事由是今天我在用 create-react-app 新建一个用于测试的前端项目。 然后就出现以下报错&#xff1a; wuyuj…

Linux e2fsck命令教程:如何检查和修复文件系统(附案例详解和注意事项)

Linux e2fsck命令介绍 e2fsck是一个用于检查Linux第二扩展文件系统&#xff08;ext2fs&#xff09;的命令。它也支持包含日志的ext2文件系统&#xff0c;这些文件系统有时也被称为ext3文件系统。该命令会自动保存找到的坏块到文件系统中&#xff0c;以便这些硬盘的部分不再被使…

有文件实体的后门无文件实体的后门rootkit后门

有文件实体后门和无文件实体后门&RootKit后门 什么是有文件的实体后门&#xff1a; 在传统的webshell当中&#xff0c;后门代码都是可以精确定位到某一个文件上去的&#xff0c;你可以rm删除它&#xff0c;可以鼠标右键操作它&#xff0c;它是有一个文件实体对象存在的。…

优化你的计算机性能:如何根据 CPU 占用率决定硬件升级

优化你的计算机性能&#xff1a;如何根据 CPU 占用率决定硬件升级 一、引言二、CPU 占用率的意义与影响三、监测和评估 CPU 占用率四、判断硬件升级需求的依据五、硬件升级方案和建议六、总结 一、引言 计算机性能优化是提升计算机系统整体效能的过程&#xff0c;它对于用户和…

Mac苹果视频剪辑:Final Cut Pro Mac

Final Cut Pro是一款由Apple公司开发的专业视频非线性编辑软件&#xff0c;是业界著名的视频剪辑软件之一。它最初发布于1999年&#xff0c;是Mac电脑上的一款独占软件。Final Cut Pro具有先进的剪辑工具、丰富的特效和颜色分级、音频处理等功能&#xff0c;使得用户可以轻松地…

Ext4文件系统解析(二)

1、前言 想要了解EXT文件系统的工作原理&#xff0c;那了解文件系统在磁盘上的分布就是必不可少的。这一节主要介绍EXT文件系统硬盘存储的物理结构。 由于当前主流的CPU架构均采用小端模式&#xff0c;因此下文介绍均已小端模式为准。 2、超级块 2.1 属性 下表列举出超级块…

OpenCV-Python:计算机视觉介绍

目录 1.背景 2.计算机视觉发展历史 3.计算机视觉主要任务 4.计算机视觉应用场景 5.知识笔记 1.背景 OpenCV是计算机视觉的一个框架&#xff0c;想要学习OpenCV&#xff0c;需要对计算机视觉有一个大致的了解。计算机视觉是指通过计算机技术和算法来模拟人类视觉系统的能力…