当前位置: 首页 > news >正文

建网站哪家好案例网站建设会考什么

建网站哪家好案例,网站建设会考什么,摄影网页,wordpress仿FFmpeg之如何新增一个硬件解码器 前言一、config配置二、解码器定义1.目录结构2.数据结构 三、解码流程1、初始化mediacodec_decode_init2、帧接收mediacodec_receive_frame2.1 解码上下文MediaCodecH264DecContext2.2 发包AVPacket到解码器 -- ff_mediacodec_dec_send2.3 接收… FFmpeg之如何新增一个硬件解码器 前言一、config配置二、解码器定义1.目录结构2.数据结构 三、解码流程1、初始化mediacodec_decode_init2、帧接收mediacodec_receive_frame2.1 解码上下文MediaCodecH264DecContext2.2 发包AVPacket到解码器 -- ff_mediacodec_dec_send2.3 接收解码后数据AVFrame -- ff_mediacodec_dec_receive 3、刷新缓冲区mediacodec_decode_flush4、关闭解码器mediacodec_decode_close 四、回顾与总结 前言 最近在鸿蒙上开发音视频相关功能在适配好SDL2之后接入FFmpeg软解即可播放音视频然对于4k大码率的视频播放时却非常卡顿。于是乎琢磨着在鸿蒙上加一个FFmpeg的硬解码PS鸿蒙官方目前只提供解码相关 SDK。不过应该如何入手呢想到这个鸿蒙跟安卓还是有点类似解码都是异步回调机制于是先捋一遍安卓下硬解码流程吧。 一、config配置 首先MediaCodec是Android平台提供的底层音视频编解码API支持解码的格式有 视频H.264(AVC)、H.265(HEVC)、VP8、VP9、MPEG-4、AV1  音频AAC、MP3、Opus 下面以H.264格式为例在configure文件中有以下两行 h264_mediacodec_decoder_depsmediacodec h264_mediacodec_decoder_selecth264_mp4toannexb_bsf h264_parser第一行mediacodec表示该解码器依赖 Android 的 MediaCodec API在配置阶段configure 脚本会通过配置的NDK路径检测系统中是否存在这些依赖项   第二行声明该解码器的关联组件当 h264_mediacodec_decoder 被启用时configure 会自动启用以下组件 h264_mp4toannexb_bsf将 H.264 码流从 MP4 封装格式AVCC转换为 Annex B 格式。【这个后面会用到稍后再讲~】  h264_parserH.264 码流解析器用于解析码流中的 NALU 单元。. 在命令行指定一下相关参数即可开启硬件解码 ./configure \--target-osandroid \--archarm64 \--enable-cross-compile \--sysroot$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot \--enable-mediacodec \--enable-decoderh264_mediacodec生成的MakeFile文件中有一行 OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) mediacodecdec.o二、解码器定义 1.目录结构 在libavcodec目录下mediacodec相关的文件有12个如下 2.数据结构 首先我们可以看下mediacodecdec.c中DECLARE_MEDIACODEC_VDEC相关的宏定义 #define DECLARE_MEDIACODEC_VCLASS(short_name) \ static const AVClass ff_##short_name##_mediacodec_dec_class { \.class_name #short_name _mediacodec, /* 注册到 FFmpeg 的类名 */ \.item_name av_default_item_name, /* 默认的对象名称生成器 */ \.option ff_mediacodec_vdec_options, /* 解码器配置选项指针 */ \.version LIBAVUTIL_VERSION_INT, /* 版本号对齐校验 */ \ };#define DECLARE_MEDIACODEC_VDEC(short_name, full_name, codec_id, bsf) \ DECLARE_MEDIACODEC_VCLASS(short_name) /* 先声明 AVClass */ \ const FFCodec ff_ ## short_name ## _mediacodec_decoder { \.p.name #short_name _mediacodec, /* 解码器名称 */ \CODEC_LONG_NAME(full_name Android MediaCodec decoder), /* 长描述 */ \.p.type AVMEDIA_TYPE_VIDEO, /* 媒体类型视频 */ \.p.id codec_id, /* FFmpeg 编解码ID */ \.p.priv_class ff_##short_name##_mediacodec_dec_class, /* 私有类指针 */ \.priv_data_size sizeof(MediaCodecH264DecContext), /* 私有数据区大小 */ \.init mediacodec_decode_init, /* 初始化回调函数 */ \FF_CODEC_RECEIVE_FRAME_CB(mediacodec_receive_frame), /* 帧接收回调 */ \.flush mediacodec_decode_flush, /* 冲刷缓冲区回调 */ \.close mediacodec_decode_close, /* 关闭解码器回调 */ \.p.capabilities AV_CODEC_CAP_DELAY | /* 支持延迟输出 */ \AV_CODEC_CAP_AVOID_PROBING | /* 避免格式探测 */ \AV_CODEC_CAP_HARDWARE, /* 硬件加速标志 */ \.caps_internal FF_CODEC_CAP_NOT_INIT_THREADSAFE, /* 非线程安全初始化 */ \.bsfs bsf, /* 关联的比特流过滤器 */ \.hw_configs mediacodec_hw_configs, /* 硬件配置信息表 */ \.p.wrapper_name mediacodec, /* 封装器名称 */ \ };#if CONFIG_H264_MEDIACODEC_DECODER /* 实例化 H.264 解码器结构体 */ DECLARE_MEDIACODEC_VDEC(h264, /* 短名称 */H.264, /* 标准名称 */AV_CODEC_ID_H264, /* FFmpeg 编码ID */h264_mp4toannexb) /* MP4 到 Annex-B 格式转换器 */ #endif其中先声明一个AVClass 结构体这个是FFmpeg 的类系统核心用于统一管理编解码器的元数据注册FFCodec解码器   然后就是在解码器中注册四个回调函数mediacodec_decode_init初始化、mediacodec_receive_frame帧接收、mediacodec_decode_flush刷新缓冲区、mediacodec_decode_close关闭解码器   最后可以看到capabilities属性中的AV_CODEC_CAP_HARDWARE标志这个就是开启硬件加速比较关键如果没有这个标志那么就是用的软解了。 三、解码流程 1、初始化mediacodec_decode_init mediacodec_decode_init里面主要做了两件事   一、设置FFAMediaFormat媒体格式的一些属性如MIME类型、context的宽和高等 // h264对应的MIME为video/avcff_AMediaFormat_setString(format, mime, codec_mime);ff_AMediaFormat_setInt32(format, width, avctx-width);ff_AMediaFormat_setInt32(format, height, avctx-height);最后通过调用NDK里面的相关函数设置没有NDK的话就通过jni去调java的? 没细究 0.o   二、ff_mediacodec_dec_init其中首先通过 s-codec_name ff_AMediaCodecList_getCodecNameByType(mime, profile, 0, avctx); s-codec ff_AMediaCodec_createCodecByName(s-codec_name, s-use_ndk_codec);获取解码器名称并创建解码器然后再配置解码器并启动 status ff_AMediaCodec_configure(s-codec, format, s-surface, NULL, 0); status ff_AMediaCodec_start(s-codec);上述函数均有NDK和JNI两套调用逻辑。 2、帧接收mediacodec_receive_frame mediacodec_receive_frame是从解码器中获取解码后的视频帧里面的核心流程是异步处理输入和输出缓冲区通过队列管理。当ff_mediacodec_dec_send被调用时AVPacket数据会被放入输入队列等待解码器处理。解码后的数据则从输出队列中取出即ff_mediacodec_dec_receive函数负责从输出队列获取解码后的帧AVFrame。 2.1 解码上下文MediaCodecH264DecContext 不过在这之前首先来看下解码器上下文MediaCodecH264DecContext这个关键类的数据结构设计 // H264 MediaCodec解码器上下文: typedef struct MediaCodecH264DecContext {//AVClass 集成到FFmpeg的类系统中用于日志记录、私有选项配置及参数解析AVClass *avclass;//MediaCodecDecContext指向通用的MediaCodec解码器上下文,h264只是其中的一个特化MediaCodecDecContext *ctx;//当输入数据包过大无法一次性写入硬件缓冲区时剩余数据暂存于此等待后续处理AVPacket buffered_pkt;//延迟刷新解码器的标志确保所有已提交数据被处理后再执行刷新int delay_flush;int amlogic_mpeg2_api23_workaround; // ?// NDK API更高效减少Java层交互开销适用于高性能需求场景int use_ndk_codec; } MediaCodecH264DecContext;//通用的MediaCodec解码器上下文管理硬件解码器状态: typedef struct MediaCodecDecContext {AVCodecContext *avctx; //FFmpeg编解码上下文用于日志和配置信息atomic_int refcount;atomic_int hw_buffer_count;char *codec_name;FFAMediaCodec *codec;FFAMediaFormat *format;void *surface; // FFANativeWindow * 渲染表面用于零拷贝int started;int draining;int flushing;int eos;int width;int height;int stride;int slice_height;int color_format;int crop_top;int crop_bottom;int crop_left;int crop_right;int display_width;int display_height;uint64_t output_buffer_count;ssize_t current_input_buffer;bool delay_flush;atomic_int serial;bool use_ndk_codec; } MediaCodecDecContext;在提交缓冲区给解码器解码的过程中一般来说可以通过Surface上面的void *surface就是指向渲染表面或DMA 缓冲区共享技术实现零拷贝减少 CPU 与 GPU 间的数据传输避免解码过慢。 2.2 发包AVPacket到解码器 – ff_mediacodec_dec_send // 尝试获取输入缓冲区索引 index ff_AMediaCodec_dequeueInputBuffer(codec, input_dequeue_timeout_us); // 获取输入缓冲区的内存地址data和容量size data ff_AMediaCodec_getInputBuffer(codec, index, size); // 提交输入缓冲区到解码器 status ff_AMediaCodec_queueInputBuffer(codec, index, 0, size, pts, 0);2.3 接收解码后数据AVFrame – ff_mediacodec_dec_receive //: 从解码器输出队列中获取缓冲区索引 index ff_AMediaCodec_dequeueOutputBuffer(codec, info, output_dequeue_timeout_us); ... if (info.size) {// Surface 模式通过 ANativeWindow 直接渲染到 Surface无需拷贝数据。if (s-surface) {if ((ret mediacodec_wrap_hw_buffer(avctx, s, index, info, frame)) 0) {av_log(avctx, AV_LOG_ERROR, Failed to wrap MediaCodec buffer\n);return ret;}// ByteBuffer 模式将 MediaCodec 的 ByteBuffer 数据复制到 AVFrame-data} else {data ff_AMediaCodec_getOutputBuffer(codec, index, size);if (!data) {av_log(avctx, AV_LOG_ERROR, Failed to get output buffer\n);return AVERROR_EXTERNAL;}if ((ret mediacodec_wrap_sw_buffer(avctx, s, data, size, index, info, frame)) 0) {av_log(avctx, AV_LOG_ERROR, Failed to wrap MediaCodec buffer\n);return ret;}}s-output_buffer_count;return 0; } else {status ff_AMediaCodec_releaseOutputBuffer(codec, index, 0);if (status 0) {av_log(avctx, AV_LOG_ERROR, Failed to release output buffer\n);} } ... if (ff_AMediaCodec_infoOutputBuffersChanged(codec, index)) {ff_AMediaCodec_cleanOutputBuffers(codec); // 清理旧缓冲区 }3、刷新缓冲区mediacodec_decode_flush mediacodec_decode_flush在视频播放中当用户跳转进度时需要清空之前的解码数据这时候就会调用flush函数。 static void mediacodec_decode_flush(AVCodecContext *avctx) {MediaCodecH264DecContext *s avctx-priv_data;//av_packet_unref是FFmpeg中释放AVPacket资源的函数//这里是释放MediaCodecH264DecContext 中缓存的未完全提交到硬件解码器的 AVPacket 数据包av_packet_unref(s-buffered_pkt);//清空解码器的输入/输出缓冲区若解码器正在处理数据Executing 状态flush会强制停止当前操作ff_mediacodec_dec_flush(avctx, s-ctx); }一般来说一下四种场景会调用flush   a、视频播放器跳转进度:     用户拖动进度条时需清空当前解码队列避免旧数据与新位置的数据混合。   b、处理解码错误     当解码器因数据错误进入异常状态时通过刷新重置其状态恢复解码能力。   c、格式动态切换     切换分辨率或码率时需先清空原有数据再重新配置解码器。   d、结束流或重新初始化     在流结束或重新初始化解码器前确保资源正确释放。 4、关闭解码器mediacodec_decode_close 通过引用计数管理声明周期计数为0时依次删除MediaCodec、MediaFormat和Surface等对象最后删除MediaCodecDecContext。 static void ff_mediacodec_dec_unref(MediaCodecDecContext *s) {...// 原子操作引用计数减1若原值为1减后为0则释放资源if (atomic_fetch_sub(s-refcount, 1) 1) {ff_AMediaCodec_delete(s-codec); ff_AMediaFormat_delete(s-format);ff_mediacodec_surface_unref(s-surface, NULL);} }四、回顾与总结 综上所述FFmpeg添加一个硬件解码器的关键步骤如下 步骤关键操作1. 配置编译修改 configure 和 Makefile添加新解码器选项2. 定义结构体注册 AVCodec实现编解码器上下文3. 初始化与配置创建 MediaCodec 实例设置格式参数4. 数据传递实现 send_packet 和 receive_frame适配硬件缓冲区5. 资源管理处理刷新、关闭和引用计数确保无内存泄漏 整体来说硬件解码核心流程并不复杂主要是要对NDK中的接口调用以及处理相比于软件解码来说主要是在数据在CPU和GPU之间传输的不同虽然硬件解码后支持GPU直接渲染无需数据回传不过若需要CPU处理如滤镜还需将数据从显存拷贝到系统内存。因此现代播放器常结合两者优先尝试硬件解码失败时回退到软件解码。鸿蒙平台和安卓很类似无非是NDK不同罢了不过NDK里面怎么写的那就不得而知了。(-_-
http://www.hkea.cn/news/14386495/

相关文章:

  • 公司招聘网站排行榜成都网页设计培训中心
  • 网站排名有什么用软件技术就业前景分析
  • 商城网站建设基础设计网络工程师报名时间
  • 钦州电商网站建设wordpress图片自动分页
  • 威联通nas 做网站广州网络营销十年乐云seo
  • 松原网站建设哪家好wordpress滑动菜单
  • 织梦做网站的教程软文写作500字
  • 足彩彩票网站建设wordpress js版
  • 网站备案号 如何添加网络营销实训个人总结
  • 单页网站编辑器北京招聘网站开发
  • 某某公司网站建设论文wordpress进入文字版
  • 无锡市太湖新城建设网站网站改版对网站优化影响最大的问题是什么
  • 网站建设 重点做网站的挣钱么
  • 苏通建设集团有限公司网站阳江网红服务区
  • 电商网站建设是做什么的网站建设代理平台怎么做
  • 河南住房和城乡建设厅网站首页企业做电商网站有哪些内容
  • 单县建设局网站深圳企业网站哪家好
  • 网站建设描述延吉市网站建设
  • 网站 业务范围公司后台的网站代理维护更新
  • 建设网站需要什么知识更改wordpress最大上传文件大小
  • 做网站源码要给客户嘛沧州 网站建设
  • 营销型网站效果设计广告图片用什么软件
  • 静态网站建设的PPT工业和信息化部电子第五研究所
  • 金融集团网站模板租房网站开发报告
  • 网站外链建设:论坛签名是否还值得做目前流行的网站分辨率做多大
  • 现在流行做网站吗如何做电影网站才不侵权
  • 企业网站开发期末报告Wordpress设置Ip不开放
  • 河南建设168工程网官方网站如何建立一个网站请简述流程
  • 网站空间密码临沂河东区建设局网站
  • 个人做网站公司手机网页设计制作网站