libaom 源码分析:scalable_decoder.c 文件

libaom

  1. 基本特性

    • 开放和免版税:libaom 提供了一个开放源代码的编码器,任何个人和组织都可以免费使用,无需支付版税,这促进了它在各种应用中的广泛采用。
    • 高效的编码:旨在提供高效的视频压缩,以适应不同的网络条件和设备性能。AV1 编解码器通常比 HEVC(H.265)提供约 30% 更好的压缩效率,在相同质量下可以减少带宽消耗。
    • 先进的压缩技术:实现了 AV1 编解码器,使用了一系列先进的压缩技术,如 CDEF(Constrained Directional Enhancement Filtering)、CIC(Compound Internal Coding)和 PAET(Probabilistic Angular Early Termination)等。
    • 可配置性:提供了多种配置选项,允许开发者根据应用需求调整编码参数。
    • 实时编码支持:支持实时编码,适用于直播和实时通信应用。
    • 社区支持:作为一个开源项目,得到了活跃的社区支持,不断有新功能和改进被加入。
  2. 应用场景
    libaom 可以用于各种需要视频编解码的场景,如在线视频播放、视频会议、视频存储、流媒体、网页视频等。许多视频播放器、浏览器和视频服务提供商都采用了 libaom 来实现 AV1 视频编码标准。

  3. 性能提升

    • 压缩性能:经过团队的研究和尝试,AV1 的压缩性能在过去几年中有了显著的提高,相对于 VP9 而言,在以 PSNR 或 SSIM 这样的客观指标条件下能提高 36% 以上。
    • 编码器速度和内存需求:相对于 2018 年 bit - stream finalization 的时候,Libaom 编码器的速度提升 150 倍以上,在 4K 的视频压缩条件下对内存的需求下降了 80%。同时,Libaom 支持不同的 speed setting,用户可以根据实际需求进行选择,在速度和压缩性能之间进行平衡。

scalable_decoder.c 介绍

  1. 功能描述:该文件是一个可伸缩解码器的示例,输入文件包含两层空间层的压缩数据,格式为 OBU,数据通过解码器处理,解码后的帧会写入磁盘,基本层和增强层分别存储为 out_lyr0.yuvout_lyr1.yuv 文件。
  2. 文件位置:libaom/examples/scalable_decoder.c
  3. main 函数流程梳理
. 初始化阶段- 解析命令行参数,检查输入文件- 打开输入文件并初始化 OBU 解码上下文- 获取 AV1 解码器接口- 初始化解码器上下文- 设置解码器输出所有层的控制参数. 文件验证- 读取文件头信息,验证是否为有效的 OBU 文件- 获取视频流的空间层数量. 输出文件准备- 打开基本层输出文件 `out_lyr0.yuv`- 根据空间层数量打开对应的增强层输出文件. 解码循环- 读取时间单元数据- 解码每一帧- 获取解码后的图像- 对图像进行位深转换- 根据空间层 ID 将图像写入对应的输出文件- 更新帧计数器. 清理阶段- 销毁解码器上下文- 关闭所有输出文件- 关闭输入文件
  1. 文件内部调用的 API 解析
  • 实例化解码器:get_aom_decoder_by_index(0) 通过索引 0 获取 AV1 解码器接口,aom_codec_iface_name(decoder) 获取解码器的名称;
  aom_codec_iface_t *decoder = get_aom_decoder_by_index(0);printf("Using %s\n", aom_codec_iface_name(decoder));
  • 初始化:aom_codec_ctx_t codec声明一个解码器上下文变量 codec ,用于存储解码器的状态信息;aom_codec_dec_init() 初始化解码器;
  aom_codec_ctx_t codec;if (aom_codec_dec_init(&codec, decoder, NULL, 0))die("Failed to initialize decoder.");
  • 编码器能力控制:aom_codec_control() 用于设置解码器的控制参数;
    AV1D_SET_OUTPUT_ALL_LAYERS 控制参数,表示是否输出所有层;
 if (aom_codec_control(&codec, AV1D_SET_OUTPUT_ALL_LAYERS, 1)) {die_codec(&codec, "Failed to set output_all_layers control.");}
  • 输入流的OBU头信息解析:aom_codec_peek_stream_info解析空间层配置信息;
  // peak sequence header OBU to get number of spatial layersconst size_t ret = fread(tmpbuf, 1, 32, inputfile);if (ret != 32) die_codec(&codec, "Input is not a valid obu file");si.is_annexb = 0;if (aom_codec_peek_stream_info(decoder, tmpbuf, 32, &si)) {die_codec(&codec, "Input is not a valid obu file");}fseek(inputfile, -32, SEEK_CUR);
  • 文件校验和输出文件准备
 if (!file_is_obu(&obu_ctx))die_codec(&codec, "Input is not a valid obu file");// open base layer output yuv filesnprintf(filename, sizeof(filename), "out_lyr%d.yuv", 0);if (!(outfile[0] = fopen(filename, "wb")))die("Failed top open output for writing.");// open any enhancement layer output yuv filesfor (i = 1; i < si.number_spatial_layers; i++) {snprintf(filename, sizeof(filename), "out_lyr%u.yuv", i);if (!(outfile[i] = fopen(filename, "wb")))die("Failed to open output for writing.");}
  • 解码核心逻辑:obudec_read_temporal_unit一直读取OBU单元,aom_codec_decode解码的核心函数,aom_codec_get_frame获取解码帧,aom_img_downshift将原图像进行下采样,aom_img_write根据不同的spatial_id写入输出视频文件;
  while (!obudec_read_temporal_unit(&obu_ctx, &buf, &bytes_in_buffer,&buffer_size)) {aom_codec_iter_t iter = NULL;aom_image_t *img = NULL;if (aom_codec_decode(&codec, buf, bytes_in_buffer, NULL))die_codec(&codec, "Failed to decode frame.");while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) {aom_image_t *img_shifted =aom_img_alloc(NULL, AOM_IMG_FMT_I420, img->d_w, img->d_h, 16);img_shifted->bit_depth = 8;aom_img_downshift(img_shifted, img,img->bit_depth - img_shifted->bit_depth);if (img->spatial_id == 0) {printf("Writing        base layer 0 %d\n", frame_cnt);aom_img_write(img_shifted, outfile[0]);} else if (img->spatial_id <= (int)(si.number_spatial_layers - 1)) {printf("Writing enhancement layer %d %d\n", img->spatial_id, frame_cnt);aom_img_write(img_shifted, outfile[img->spatial_id]);} else {die_codec(&codec, "Invalid bitstream. Layer id exceeds layer count");}if (img->spatial_id == (int)(si.number_spatial_layers - 1)) ++frame_cnt;}}
  • 资源销毁和回收清理工作
  printf("Processed %d frames.\n", frame_cnt);if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");for (i = 0; i < si.number_spatial_layers; i++) fclose(outfile[i]);fclose(inputfile);
  1. 源码:
/** Copyright (c) 2018, Alliance for Open Media. All rights reserved.** This source code is subject to the terms of the BSD 2 Clause License and* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License* was not distributed with this source code in the LICENSE file, you can* obtain it at www.aomedia.org/license/software. If the Alliance for Open* Media Patent License 1.0 was not distributed with this source code in the* PATENTS file, you can obtain it at www.aomedia.org/license/patent.*/// Scalable Decoder
// ==============
//
// This is an example of a scalable decoder loop. It takes a 2-spatial-layer
// input file
// containing the compressed data (in OBU format), passes it through the
// decoder, and writes the decompressed frames to disk. The base layer and
// enhancement layers are stored as separate files, out_lyr0.yuv and
// out_lyr1.yuv, respectively.
//
// Standard Includes
// -----------------
// For decoders, you only have to include `aom_decoder.h` and then any
// header files for the specific codecs you use. In this case, we're using
// av1.
//
// Initializing The Codec
// ----------------------
// The libaom decoder is initialized by the call to aom_codec_dec_init().
// Determining the codec interface to use is handled by AvxVideoReader and the
// functions prefixed with aom_video_reader_. Discussion of those functions is
// beyond the scope of this example, but the main gist is to open the input file
// and parse just enough of it to determine if it's a AVx file and which AVx
// codec is contained within the file.
// Note the NULL pointer passed to aom_codec_dec_init(). We do that in this
// example because we want the algorithm to determine the stream configuration
// (width/height) and allocate memory automatically.
//
// Decoding A Frame
// ----------------
// Once the frame has been read into memory, it is decoded using the
// `aom_codec_decode` function. The call takes a pointer to the data
// (`frame`) and the length of the data (`frame_size`). No application data
// is associated with the frame in this example, so the `user_priv`
// parameter is NULL. The `deadline` parameter is left at zero for this
// example. This parameter is generally only used when doing adaptive post
// processing.
//
// Codecs may produce a variable number of output frames for every call to
// `aom_codec_decode`. These frames are retrieved by the
// `aom_codec_get_frame` iterator function. The iterator variable `iter` is
// initialized to NULL each time `aom_codec_decode` is called.
// `aom_codec_get_frame` is called in a loop, returning a pointer to a
// decoded image or NULL to indicate the end of list.
//
// Processing The Decoded Data
// ---------------------------
// In this example, we simply write the encoded data to disk. It is
// important to honor the image's `stride` values.
//
// Cleanup
// -------
// The `aom_codec_destroy` call frees any memory allocated by the codec.
//
// Error Handling
// --------------
// This example does not special case any error return codes. If there was
// an error, a descriptive message is printed and the program exits. With
// few exceptions, aom_codec functions return an enumerated error status,
// with the value `0` indicating success.#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include "aom/aom_decoder.h"
#include "aom/aomdx.h"
#include "common/obudec.h"
#include "common/tools_common.h"
#include "common/video_reader.h"static const char *exec_name;#define MAX_LAYERS 5void usage_exit(void) {fprintf(stderr, "Usage: %s <infile>\n", exec_name);exit(EXIT_FAILURE);
}int main(int argc, char **argv) {int frame_cnt = 0;FILE *outfile[MAX_LAYERS];char filename[80];FILE *inputfile = NULL;uint8_t *buf = NULL;size_t bytes_in_buffer = 0;size_t buffer_size = 0;struct AvxInputContext aom_input_ctx;struct ObuDecInputContext obu_ctx = { &aom_input_ctx, NULL, 0, 0, 0 };aom_codec_stream_info_t si;uint8_t tmpbuf[32];unsigned int i;exec_name = argv[0];if (argc != 2) die("Invalid number of arguments.");if (!(inputfile = fopen(argv[1], "rb")))die("Failed to open %s for read.", argv[1]);obu_ctx.avx_ctx->file = inputfile;obu_ctx.avx_ctx->filename = argv[1];aom_codec_iface_t *decoder = get_aom_decoder_by_index(0);printf("Using %s\n", aom_codec_iface_name(decoder));aom_codec_ctx_t codec;if (aom_codec_dec_init(&codec, decoder, NULL, 0))die("Failed to initialize decoder.");if (aom_codec_control(&codec, AV1D_SET_OUTPUT_ALL_LAYERS, 1)) {die_codec(&codec, "Failed to set output_all_layers control.");}// peak sequence header OBU to get number of spatial layersconst size_t ret = fread(tmpbuf, 1, 32, inputfile);if (ret != 32) die_codec(&codec, "Input is not a valid obu file");si.is_annexb = 0;if (aom_codec_peek_stream_info(decoder, tmpbuf, 32, &si)) {die_codec(&codec, "Input is not a valid obu file");}fseek(inputfile, -32, SEEK_CUR);if (!file_is_obu(&obu_ctx))die_codec(&codec, "Input is not a valid obu file");// open base layer output yuv filesnprintf(filename, sizeof(filename), "out_lyr%d.yuv", 0);if (!(outfile[0] = fopen(filename, "wb")))die("Failed top open output for writing.");// open any enhancement layer output yuv filesfor (i = 1; i < si.number_spatial_layers; i++) {snprintf(filename, sizeof(filename), "out_lyr%u.yuv", i);if (!(outfile[i] = fopen(filename, "wb")))die("Failed to open output for writing.");}while (!obudec_read_temporal_unit(&obu_ctx, &buf, &bytes_in_buffer,&buffer_size)) {aom_codec_iter_t iter = NULL;aom_image_t *img = NULL;if (aom_codec_decode(&codec, buf, bytes_in_buffer, NULL))die_codec(&codec, "Failed to decode frame.");while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) {aom_image_t *img_shifted =aom_img_alloc(NULL, AOM_IMG_FMT_I420, img->d_w, img->d_h, 16);img_shifted->bit_depth = 8;aom_img_downshift(img_shifted, img,img->bit_depth - img_shifted->bit_depth);if (img->spatial_id == 0) {printf("Writing        base layer 0 %d\n", frame_cnt);aom_img_write(img_shifted, outfile[0]);} else if (img->spatial_id <= (int)(si.number_spatial_layers - 1)) {printf("Writing enhancement layer %d %d\n", img->spatial_id, frame_cnt);aom_img_write(img_shifted, outfile[img->spatial_id]);} else {die_codec(&codec, "Invalid bitstream. Layer id exceeds layer count");}if (img->spatial_id == (int)(si.number_spatial_layers - 1)) ++frame_cnt;}}printf("Processed %d frames.\n", frame_cnt);if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");for (i = 0; i < si.number_spatial_layers; i++) fclose(outfile[i]);fclose(inputfile);return EXIT_SUCCESS;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/37942.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C#语言】C#同步与异步编程深度解析:让程序学会“一心多用“

文章目录 ⭐前言⭐一、同步编程&#xff1a;单线程的线性世界&#x1f31f;1、寻找合适的对象✨1) &#x1f31f;7、设计应支持变化 ⭐二、异步编程&#xff1a;多任务的协奏曲⭐三、async/await工作原理揭秘⭐四、最佳实践与性能陷阱⭐五、异步编程适用场景⭐六、性能对比实测…

[OpenCV】相机标定之棋盘格角点检测与绘制

在OpenCV中&#xff0c;棋盘格角点检测与绘制是一个常见的任务&#xff0c;通常用于相机标定。 棋盘格自定义可参考: OpenCV: Create calibration pattern 目录 1. 棋盘格角点检测 findChessboardCorners()2. 棋盘格角点绘制 drawChessboardCorners()3. 代码示例C版本python版本…

AI-Talk开发板之更换串口引脚

一、默认引脚 CSK6011A使用UART0作为Debug uart&#xff0c;AI-Talk开发板默认使用的GPIOA2和GPIOA3作为Debug uart的RX和TX&#xff0c;通过连接器CN6引出。 二 、更换到其它引脚 查看60xx_iomux_v1.0可以&#xff0c;UART0的tx和rx可以映射到很多管脚上。 结合AI-Talk开发板…

QT Quick(C++)跨平台应用程序项目实战教程 3 — 项目基本设置(窗体尺寸、中文标题、窗体图标、可执行程序图标)

目录 1. 修改程序界面尺寸和标题 2. 窗体图标 3. 修改可执行程序图标 上一章创建好了一个初始Qt Quick项目。本章介绍基本的项目修改方法。 1. 修改程序界面尺寸和标题 修改Main.qml文件&#xff0c;将程序宽度设置为1200&#xff0c;程序高度设置为800。同时修改程序标题…

【STM32实物】基于STM32的太阳能充电宝设计

基于STM32的太阳能充电宝设计 演示视频: 基于STM32的太阳能充电宝设计 硬件组成: 系统硬件包括主控 STM32F103C8T6、0.96 OLED 显示屏、蜂鸣器、电源自锁开关、温度传感器 DS18B20、继电器、5 V DC 升压模块 、TB4056、18650锂电池、9 V太阳能板、稳压降压 5 V三极管。 功能…

003-掌控命令行-CLI11-C++开源库108杰

首选的现代C风格命令行参数解析器! &#xff08;本课程包含两段教学视频。&#xff09; 以文件对象监控程序为实例&#xff0c;五分钟实现从命令行读入多个监控目标路径&#xff1b;区分两大时机&#xff0c;学习 CLI11 构建与解析参数两大场景下的异常处理&#xff1b;区分三…

OpenCV图像拼接(2)基于羽化(feathering)技术的图像融合算法拼接类cv::detail::FeatherBlender

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::detail::FeatherBlender 是 OpenCV 中用于图像拼接的一个类&#xff0c;它属于 stitching 模块的一部分。这个类实现了基于羽化&#xff08;…

如何用Function Calling解锁OpenAI的「真实世界」交互能力?(附Node.js 实战)

一、Function Calling&#xff1a;大模型的「手脚延伸器」 1.1 核心定义 Function Calling是OpenAI在2023年6月13日推出的革命性功能&#xff08;对应模型版本gpt-3.5-turbo-0613和gpt-4-0613&#xff09;&#xff0c;允许开发者通过自然语言指令触发预定义函数&#xff0c;实…

鸿蒙ArkTS+ArkUI实现五子棋游戏

鸿蒙ArkTSArkUI实现五子棋游戏 前言 近期&#xff0c;鸿蒙系统热度飙升&#xff0c;引发了周围众多朋友的热烈探讨。出于这份浓厚的好奇心&#xff0c;我初步浏览了其官方文档&#xff0c;发现信息量庞大&#xff0c;全面消化需耗时良久并考验人的毅力。自踏入编程领域以来&am…

单元测试mock

一、背景 现在有A类,B类,C类&#xff0c;A类依赖B类,依赖C类&#xff0c;如果想要测试A类中的某个方法的业务逻辑。A类依赖其他类&#xff0c;则把其他类给mock&#xff0c;然后A类需要真实对象。这样就可以测试A类中的方法。 举例&#xff1a;Ticket类需要调用Flight类和Pas…

深度学习篇---深度学习中的范数

文章目录 前言一、向量范数1.L0范数1.1定义1.2计算式1.3特点1.4应用场景1.4.1特征选择1.4.2压缩感知 2.L1范数&#xff08;曼哈顿范数&#xff09;2.1定义2.2计算式2.3特点2.4应用场景2.4.1L1正则化2.4.2鲁棒回归 3.L2范数&#xff08;欧几里得范数&#xff09;3.1定义3.2特点3…

JVM常见概念之条件移动

问题 当我们有分支频率数据时&#xff0c;有什么有趣的技巧可以做吗&#xff1f;什么是条件移动&#xff1f; 基础知识 如果您需要在来自一个分支的两个结果之间进行选择&#xff0c;那么您可以在 ISA 级别做两件不同的事情。 首先&#xff0c;你可以创建一个分支&#xff…

Debug-037-table列表勾选回显方案

效果展示&#xff1a; 图1 图2 最近实现一个支持勾选的el-table可以回显之前勾选项的功能。实现了一个“编辑”的功能&#xff1a; 在图1中的列表中有三行数据&#xff0c;当点击“更换设备”按钮时&#xff0c;打开抽屉显示el-table组件如图2所示&#xff0c;可以直接回显勾选…

Python散点图(Scatter Plot):数据探索的“第一张图表”

在数据可视化领域,散点图是一种强大而灵活的工具,它能够帮助我们直观地理解和探索数据集中变量之间的关系。本文将深入探讨散点图的核心原理、应用场景以及如何使用Python进行高效绘制。 后续几篇将介绍高级技巧、复杂应用场景。 Python散点图(Scatter Plot):高阶分析、散点…

docker利用ollama +Open WebGUI在本地搭建部署一套Deepseek-r1模型

系统&#xff1a;没有限制&#xff0c;可以运行docker就行 磁盘空间&#xff1a;至少预留50GB; 内存&#xff1a;8GB docker版本&#xff1a;4.38.0 桌面版 下载ollama镜像 由于docker镜像地址&#xff0c;网络不太稳定&#xff0c;建议科学上网的一台服务器拉取ollama镜像&am…

JavaScript |(六)DOM事件 | 尚硅谷JavaScript基础实战

学习来源&#xff1a;尚硅谷JavaScript基础&实战丨JS入门到精通全套完整版 笔记来源&#xff1a;在这位大佬的基础上添加了一些东西&#xff0c;欢迎大家支持原创&#xff0c;大佬太棒了&#xff1a;JavaScript |&#xff08;六&#xff09;DOM事件 | 尚硅谷JavaScript基础…

卷积神经网络 - 梯度和反向传播算法

在卷积网络中&#xff0c;参数为卷积核中权重以及偏置。和全连接前馈网络类似&#xff0c;卷积网络也可以通过误差反向传播算法来进行参数学习。本文我们从数学角度&#xff0c;来学习卷积神经网络梯度的推导和其反向传播算法的原理。 一、梯度&#xff1a;损失函数 L 关于第 …

鸿蒙NEXT项目实战-百得知识库03

代码仓地址&#xff0c;大家记得点个star IbestKnowTeach: 百得知识库基于鸿蒙NEXT稳定版实现的一款企业级开发项目案例。 本案例涉及到多个鸿蒙相关技术知识点&#xff1a; 1、布局 2、配置文件 3、组件的封装和使用 4、路由的使用 5、请求响应拦截器的封装 6、位置服务 7、三…

【测试篇】关于allpairs实现正交测试用例保姆级讲解,以及常见的错误问题

前言 &#x1f31f;&#x1f31f;本期讲解关于测试工具相关知识介绍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不多说…

OpenCV图像拼接(4)图像拼接模块的一个匹配器类cv::detail::BestOf2NearestRangeMatcher

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::detail::BestOf2NearestRangeMatcher 是 OpenCV 库中用于图像拼接模块的一个匹配器类&#xff0c;专门用于寻找两幅图像之间的最佳特征点匹配…