树莓派移植FFmepg记录(x264、硬件编码支持)

2024-02-03 04:40

本文主要是介绍树莓派移植FFmepg记录(x264、硬件编码支持),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

树莓派移植FFmepg记录(x264、硬件编码支持)

参考链接:

  • 树莓派编译安装FFmpeg(添加H.264硬件编解码器支持)_唐传林的博客-CSDN博客
  • ubuntu下交叉编译X264和FFMPEG到RK3399平台(编译器:aarch64-linux-gcc)-阿里云开发者社区 (aliyun.com)
  • FFmpeg encode_video.c示例 - 简书 (jianshu.com)

本次移植为FFmpeg添加了x264软件编码器、Omx-rpi硬件编码的支持

1.x264交叉编译

进入源码目录,根据configure --help,编写一个脚本:

#!/bin/sh./configure --prefix=./pi_install \
--enable-strip \
--disable-asm \
--host=arm-linux \
--cross-prefix=arm-linux-gnueabihf- \
--sysroot=/opt/rpi_tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/arm-linux-gnueabihf/sysroot \
--enable-shared \
# --disable-cli #配置该项不会生成可执行文件

执行后会生成makefile,执行编译命令:

make 或make -j8 #多线程编译,提高编译速度

编译完成后使用make install命令则会将生成的文件拷贝到安装目录:

boy@ubuntu:~/opensource/x264/pi_install$ tree .
.
├── bin
│   └── x264
├── include
│   ├── x264_config.h
│   └── x264.h
└── lib├── libx264.so -> libx264.so.164├── libx264.so.164└── pkgconfig└── x264.pc4 directories, 6 files
boy@ubuntu:~/opensource/x264/pi_install$

可以看到已经根据我们的configure配置项,生成了so动态库、可执行文件等。

2.ffmpeg交叉编译

源码下载链接:Download FFmpeg

解压:

tar -jxvf ffmpeg-snapshot.tar.bz2

与配置x264类似,使用configure --help可以查看到有很多选项配置,这里使用参考前人的配置编写一个合适的脚本:

#!/bin/sh./configure \
--enable-shared \
--enable-static \
--prefix=`pwd`/pi_install \
--extra-cflags=-I/home/boy/opensource/x264/pi_install/include \ #添加外部头文件路径
--extra-ldflags=-L/home/boy/opensource/x264/pi_install/lib \    #添加外部库文件路径
--enable-libx264 #使能x264编码器
--enable-cross-compile \
--cross-prefix=arm-linux-gnueabihf- \
--arch=arm \
--target-os=linux \
--enable-gpl \

**注:**这些选项貌似会有一定的先后顺序,刚开始–extra-cflags、–extra-ldflags放在后面一直编译不成功。。

生成makefile后执行make -j8进行编译,代码比较多,编译会比较慢,编译完成后make install安装到相应路径:

.
├── bin
│   ├── ffmpeg
│   └── ffprobe
├── include
│   ├── libavcodec
│   │   ├── ac3_parser.h
│   │   ├── adts_parser.h
│   │   ├── avcodec.h
│   │   ├── avdct.h
│   │   ├── avfft.h
│   │   ├── bsf.h
│   │   ├── codec_desc.h
│   │   ├── codec.h
│   │   ├── codec_id.h
│   │   ├── codec_par.h
│   │   ├── d3d11va.h
│   │   ├── defs.h
│   │   ├── dirac.h
│   │   ├── dv_profile.h
│   │   ├── dxva2.h
│   │   ├── jni.h
│   │   ├── mediacodec.h
│   │   ├── packet.h
│   │   ├── qsv.h
│   │   ├── vdpau.h
│   │   ├── version.h
│   │   ├── version_major.h
│   │   ├── videotoolbox.h
│   │   ├── vorbis_parser.h
│   │   └── xvmc.h
│   ├── libavdevice
│   │   ├── avdevice.h
│   │   ├── version.h
│   │   └── version_major.h
│   ├── libavfilter
│   │   ├── avfilter.h
│   │   ├── buffersink.h
│   │   ├── buffersrc.h
│   │   ├── version.h
│   │   └── version_major.h
│   ├── libavformat
│   │   ├── avformat.h
│   │   ├── avio.h
│   │   ├── version.h
│   │   └── version_major.h
│   ├── libavutil
│   │   ├── adler32.h
│   │   ├── aes_ctr.h
│   │   ├── aes.h
│   │   ├── attributes.h
│   │   ├── audio_fifo.h
│   │   ├── avassert.h
│   │   ├── avconfig.h
│   │   ├── avstring.h
│   │   ├── avutil.h
│   │   ├── base64.h
│   │   ├── blowfish.h
│   │   ├── bprint.h
│   │   ├── bswap.h
│   │   ├── buffer.h
│   │   ├── camellia.h
│   │   ├── cast5.h
│   │   ├── channel_layout.h
│   │   ├── common.h
│   │   ├── cpu.h
│   │   ├── crc.h
│   │   ├── des.h
│   │   ├── detection_bbox.h
│   │   ├── dict.h
│   │   ├── display.h
│   │   ├── dovi_meta.h
│   │   ├── downmix_info.h
│   │   ├── encryption_info.h
│   │   ├── error.h
│   │   ├── eval.h
│   │   ├── ffversion.h
│   │   ├── fifo.h
│   │   ├── file.h
│   │   ├── film_grain_params.h
│   │   ├── frame.h
│   │   ├── hash.h
│   │   ├── hdr_dynamic_metadata.h
│   │   ├── hdr_dynamic_vivid_metadata.h
│   │   ├── hmac.h
│   │   ├── hwcontext_cuda.h
│   │   ├── hwcontext_d3d11va.h
│   │   ├── hwcontext_drm.h
│   │   ├── hwcontext_dxva2.h
│   │   ├── hwcontext.h
│   │   ├── hwcontext_mediacodec.h
│   │   ├── hwcontext_opencl.h
│   │   ├── hwcontext_qsv.h
│   │   ├── hwcontext_vaapi.h
│   │   ├── hwcontext_vdpau.h
│   │   ├── hwcontext_videotoolbox.h
│   │   ├── hwcontext_vulkan.h
│   │   ├── imgutils.h
│   │   ├── intfloat.h
│   │   ├── intreadwrite.h
│   │   ├── lfg.h
│   │   ├── log.h
│   │   ├── lzo.h
│   │   ├── macros.h
│   │   ├── mastering_display_metadata.h
│   │   ├── mathematics.h
│   │   ├── md5.h
│   │   ├── mem.h
│   │   ├── motion_vector.h
│   │   ├── murmur3.h
│   │   ├── opt.h
│   │   ├── parseutils.h
│   │   ├── pixdesc.h
│   │   ├── pixelutils.h
│   │   ├── pixfmt.h
│   │   ├── random_seed.h
│   │   ├── rational.h
│   │   ├── rc4.h
│   │   ├── replaygain.h
│   │   ├── ripemd.h
│   │   ├── samplefmt.h
│   │   ├── sha512.h
│   │   ├── sha.h
│   │   ├── spherical.h
│   │   ├── stereo3d.h
│   │   ├── tea.h
│   │   ├── threadmessage.h
│   │   ├── timecode.h
│   │   ├── time.h
│   │   ├── timestamp.h
│   │   ├── tree.h
│   │   ├── twofish.h
│   │   ├── tx.h
│   │   ├── version.h
│   │   ├── video_enc_params.h
│   │   └── xtea.h
│   ├── libpostproc
│   │   ├── postprocess.h
│   │   ├── version.h
│   │   └── version_major.h
│   ├── libswresample
│   │   ├── swresample.h
│   │   ├── version.h
│   │   └── version_major.h
│   └── libswscale
│       ├── swscale.h
│       ├── version.h
│       └── version_major.h
├── lib
│   ├── libavcodec.a
│   ├── libavcodec.so -> libavcodec.so.59.25.100
│   ├── libavcodec.so.59 -> libavcodec.so.59.25.100
│   ├── libavcodec.so.59.25.100
│   ├── libavdevice.a
│   ├── libavdevice.so -> libavdevice.so.59.6.100
│   ├── libavdevice.so.59 -> libavdevice.so.59.6.100
│   ├── libavdevice.so.59.6.100
│   ├── libavfilter.a
│   ├── libavfilter.so -> libavfilter.so.8.29.100
│   ├── libavfilter.so.8 -> libavfilter.so.8.29.100
│   ├── libavfilter.so.8.29.100
│   ├── libavformat.a
│   ├── libavformat.so -> libavformat.so.59.20.101
│   ├── libavformat.so.59 -> libavformat.so.59.20.101
│   ├── libavformat.so.59.20.101
│   ├── libavutil.a
│   ├── libavutil.so -> libavutil.so.57.24.101
│   ├── libavutil.so.57 -> libavutil.so.57.24.101
│   ├── libavutil.so.57.24.101
│   ├── libpostproc.a
│   ├── libpostproc.so -> libpostproc.so.56.5.100
│   ├── libpostproc.so.56 -> libpostproc.so.56.5.100
│   ├── libpostproc.so.56.5.100
│   ├── libswresample.a
│   ├── libswresample.so -> libswresample.so.4.6.100
│   ├── libswresample.so.4 -> libswresample.so.4.6.100
│   ├── libswresample.so.4.6.100
│   ├── libswscale.a
│   ├── libswscale.so -> libswscale.so.6.6.100
│   ├── libswscale.so.6 -> libswscale.so.6.6.100
│   ├── libswscale.so.6.6.100
│   └── pkgconfig
│       ├── libavcodec.pc
│       ├── libavdevice.pc
│       ├── libavfilter.pc
│       ├── libavformat.pc
│       ├── libavutil.pc
│       ├── libpostproc.pc
│       ├── libswresample.pc
│       └── libswscale.pc
├── share
│   ├── ffmpeg
│   │   ├── examples
│   │   │   ├── avio_list_dir.c
│   │   │   ├── avio_reading.c
│   │   │   ├── decode_audio.c
│   │   │   ├── decode_video.c
│   │   │   ├── demuxing_decoding.c
│   │   │   ├── encode_audio.c
│   │   │   ├── encode_video.c
│   │   │   ├── extract_mvs.c
│   │   │   ├── filter_audio.c
│   │   │   ├── filtering_audio.c
│   │   │   ├── filtering_video.c
│   │   │   ├── http_multiclient.c
│   │   │   ├── hw_decode.c
│   │   │   ├── Makefile
│   │   │   ├── metadata.c
│   │   │   ├── muxing.c
│   │   │   ├── qsvdec.c
│   │   │   ├── README
│   │   │   ├── remuxing.c
│   │   │   ├── resampling_audio.c
│   │   │   ├── scaling_video.c
│   │   │   ├── transcode_aac.c
│   │   │   ├── transcoding.c
│   │   │   ├── vaapi_encode.c
│   │   │   └── vaapi_transcode.c
│   │   ├── ffprobe.xsd
│   │   ├── libvpx-1080p50_60.ffpreset
│   │   ├── libvpx-1080p.ffpreset
│   │   ├── libvpx-360p.ffpreset
│   │   ├── libvpx-720p50_60.ffpreset
│   │   └── libvpx-720p.ffpreset
│   └── man
│       ├── man1
│       │   ├── ffmpeg.1
│       │   ├── ffmpeg-all.1
│       │   ├── ffmpeg-bitstream-filters.1
│       │   ├── ffmpeg-codecs.1
│       │   ├── ffmpeg-devices.1
│       │   ├── ffmpeg-filters.1
│       │   ├── ffmpeg-formats.1
│       │   ├── ffmpeg-protocols.1
│       │   ├── ffmpeg-resampler.1
│       │   ├── ffmpeg-scaler.1
│       │   ├── ffmpeg-utils.1
│       │   ├── ffprobe.1
│       │   └── ffprobe-all.1
│       └── man3
│           ├── libavcodec.3
│           ├── libavdevice.3
│           ├── libavfilter.3
│           ├── libavformat.3
│           ├── libavutil.3
│           ├── libswresample.3
│           └── libswscale.3
└── tree.txt18 directories, 229 files

编译完成即可拷贝头文件、库文件到自己的工程目录,编写相关应用程序。

3.添加硬件编码支持

​ libx264是使用CPU进行编码转换的,即软件编码,运行起来CPU占用率非常高。为了降低CPU占用率,决定使用硬件加速编码。

首先,需要知道两个比较关键的东西:

  • omx-rpi 树莓派的硬编码加速
  • mmal 树莓派的硬解码加速

PS:博主只用到编码,因此只添加硬件编码支持,硬件解码的添加应该大同小异,有空再折腾。

​ 树莓派交叉编译添加硬件编码支持的资料非常少,折腾了非常久( ~ . ~痛苦面具),最后在某歌搜索到一个比较有用的博客:为树莓派交叉编译FFMPEG工具 | Sunrise 博客 (yjdwbj.github.io)

①.获取树莓派omx库、头文件

根据该博客的指导,在树莓派/opt/vc目录下包含有omxmmal相关的库文件、头文件以及相关的demo,如下所示,将这些拷贝到ubuntu宿主机。

boy@ubuntu:~/opensource/vc$ tree .
.
├── bin
│   ├── containers_check_frame_int
│   ├── containers_datagram_receiver
│   ├── containers_datagram_sender
│   ├── containers_dump_pktfile
│   ├── containers_rtp_decoder
│   ├── containers_stream_client
│   ├── containers_stream_server
│   ├── containers_test
│   ├── containers_test_bits
│   ├── containers_test_uri
│   ├── containers_uri_pipe
│   ├── dtmerge
│   ├── dtoverlay
│   ├── dtoverlay-post
│   ├── dtoverlay-pre
│   ├── dtparam -> dtoverlay
│   ├── edidparser
│   ├── mmal_vc_diag
│   ├── raspistill
│   ├── raspivid
│   ├── raspividyuv
│   ├── raspiyuv
│   ├── tvservice
│   ├── vcdbg
│   ├── vcgencmd
│   ├── vchiq_test
│   ├── vcmailbox
│   └── vcsmem
├── include
│   ├── bcm_host.h
│   ├── EGL
│   │   ├── eglext_android.h
│   │   ├── eglext_brcm.h
│   │   ├── eglext.h
│   │   ├── eglext_nvidia.h
│   │   ├── egl.h
│   │   └── eglplatform.h
│   ├── GLES
│   │   ├── glext.h
│   │   ├── gl.h
│   │   └── glplatform.h
│   ├── GLES2
│   │   ├── gl2ext.h
│   │   ├── gl2.h
│   │   └── gl2platform.h
│   ├── IL
│   │   ├── OMX_Audio.h
│   │   ├── OMX_Broadcom.h
│   │   ├── OMX_Component.h
│   │   ├── OMX_Core.h
│   │   ├── OMX_ILCS.h
│   │   ├── OMX_Image.h
│   │   ├── OMX_Index.h
│   │   ├── OMX_IVCommon.h
│   │   ├── OMX_Other.h
│   │   ├── OMX_Types.h
│   │   └── OMX_Video.h
│   ├── interface
│   │   ├── debug_sym
│   │   │   └── debug_sym.h
│   │   ├── mmal
│   │   │   ├── core
│   │   │   │   ├── mmal_buffer_private.h
│   │   │   │   ├── mmal_clock_private.h
│   │   │   │   ├── mmal_component_private.h
│   │   │   │   ├── mmal_core_private.h
│   │   │   │   ├── mmal_events_private.h
│   │   │   │   └── mmal_port_private.h
│   │   │   ├── mmal_buffer.h
│   │   │   ├── mmal_clock.h
│   │   │   ├── mmal_common.h
│   │   │   ├── mmal_component.h
│   │   │   ├── mmal_encodings.h
│   │   │   ├── mmal_events.h
│   │   │   ├── mmal_format.h
│   │   │   ├── mmal.h
│   │   │   ├── mmal_logging.h
│   │   │   ├── mmal_parameters_audio.h
│   │   │   ├── mmal_parameters_camera.h
│   │   │   ├── mmal_parameters_clock.h
│   │   │   ├── mmal_parameters_common.h
│   │   │   ├── mmal_parameters.h
│   │   │   ├── mmal_parameters_video.h
│   │   │   ├── mmal_pool.h
│   │   │   ├── mmal_port.h
│   │   │   ├── mmal_queue.h
│   │   │   ├── mmal_types.h
│   │   │   ├── util
│   │   │   │   ├── mmal_component_wrapper.h
│   │   │   │   ├── mmal_connection.h
│   │   │   │   ├── mmal_default_components.h
│   │   │   │   ├── mmal_graph.h
│   │   │   │   ├── mmal_il.h
│   │   │   │   ├── mmal_list.h
│   │   │   │   ├── mmal_param_convert.h
│   │   │   │   ├── mmal_util.h
│   │   │   │   ├── mmal_util_params.h
│   │   │   │   └── mmal_util_rational.h
│   │   │   └── vc
│   │   │       ├── mmal_vc_api_drm.h
│   │   │       ├── mmal_vc_api.h
│   │   │       ├── mmal_vc_client_priv.h
│   │   │       ├── mmal_vc_msgnames.h
│   │   │       ├── mmal_vc_msgs.h
│   │   │       ├── mmal_vc_opaque_alloc.h
│   │   │       └── mmal_vc_shm.h
│   │   ├── peer
│   │   │   └── vc_vchi_dispmanx_common.h
│   │   ├── vchi
│   │   │   ├── common
│   │   │   │   └── endian.h
│   │   │   ├── connections
│   │   │   │   └── connection.h
│   │   │   ├── message_drivers
│   │   │   │   └── message.h
│   │   │   ├── vchi_cfg.h
│   │   │   ├── vchi_cfg_internal.h
│   │   │   ├── vchi_common.h
│   │   │   ├── vchi.h
│   │   │   └── vchi_mh.h
│   │   ├── vchiq_arm
│   │   │   ├── vchiq_cfg.h
│   │   │   ├── vchiq.h
│   │   │   ├── vchiq_if.h
│   │   │   ├── vchiq_ioctl.h
│   │   │   ├── vchiq_test.h
│   │   │   ├── vchiq_test_if.h
│   │   │   └── vchiq_util.h
│   │   ├── vcos
│   │   │   ├── generic
│   │   │   │   ├── vcos_common.h
│   │   │   │   ├── vcos_deprecated.h
│   │   │   │   ├── vcos_generic_blockpool.h
│   │   │   │   ├── vcos_generic_event_flags.h
│   │   │   │   ├── vcos_generic_named_sem.h
│   │   │   │   ├── vcos_generic_quickslow_mutex.h
│   │   │   │   ├── vcos_generic_reentrant_mtx.h
│   │   │   │   ├── vcos_generic_tls.h
│   │   │   │   ├── vcos_joinable_thread_from_plain.h
│   │   │   │   ├── vcos_latch_from_sem.h
│   │   │   │   ├── vcos_mem_from_malloc.h
│   │   │   │   ├── vcos_mutexes_are_reentrant.h
│   │   │   │   └── vcos_thread_reaper.h
│   │   │   ├── pthreads
│   │   │   │   ├── vcos_futex_mutex.h
│   │   │   │   ├── vcos_platform.h
│   │   │   │   └── vcos_platform_types.h
│   │   │   ├── user_nodefs.h
│   │   │   ├── vcos_assert.h
│   │   │   ├── vcos_atomic_flags.h
│   │   │   ├── vcos_attr.h
│   │   │   ├── vcos_blockpool.h
│   │   │   ├── vcos_build_info.h
│   │   │   ├── vcos_cfg.h
│   │   │   ├── vcos_cmd.h
│   │   │   ├── vcos_ctype.h
│   │   │   ├── vcos_dlfcn.h
│   │   │   ├── vcos_event_flags.h
│   │   │   ├── vcos_event.h
│   │   │   ├── vcos.h
│   │   │   ├── vcos_init.h
│   │   │   ├── vcos_inttypes.h
│   │   │   ├── vcos_isr.h
│   │   │   ├── vcos_legacy_isr.h
│   │   │   ├── vcos_logging_control.h
│   │   │   ├── vcos_logging.h
│   │   │   ├── vcos_lowlevel_thread.h
│   │   │   ├── vcos_mem.h
│   │   │   ├── vcos_mempool.h
│   │   │   ├── vcos_msgqueue.h
│   │   │   ├── vcos_mutex.h
│   │   │   ├── vcos_named_semaphore.h
│   │   │   ├── vcos_once.h
│   │   │   ├── vcos_queue.h
│   │   │   ├── vcos_quickslow_mutex.h
│   │   │   ├── vcos_reentrant_mutex.h
│   │   │   ├── vcos_semaphore.h
│   │   │   ├── vcos_stdbool.h
│   │   │   ├── vcos_stdint.h
│   │   │   ├── vcos_string.h
│   │   │   ├── vcos_thread_attr.h
│   │   │   ├── vcos_thread.h
│   │   │   ├── vcos_timer.h
│   │   │   ├── vcos_tls.h
│   │   │   └── vcos_types.h
│   │   ├── vcsm
│   │   │   └── user-vcsm.h
│   │   ├── vctypes
│   │   │   ├── vc_display_types.h
│   │   │   ├── vc_image_structs.h
│   │   │   └── vc_image_types.h
│   │   └── vmcs_host
│   │       ├── khronos
│   │       │   └── IL
│   │       │       ├── OMX_Audio.h
│   │       │       ├── OMX_Broadcom.h
│   │       │       ├── OMX_Component.h
│   │       │       ├── OMX_Core.h
│   │       │       ├── OMX_ILCS.h
│   │       │       ├── OMX_Image.h
│   │       │       ├── OMX_Index.h
│   │       │       ├── OMX_IVCommon.h
│   │       │       ├── OMX_Other.h
│   │       │       ├── OMX_Types.h
│   │       │       └── OMX_Video.h
│   │       ├── linux
│   │       │   └── vchost_config.h
│   │       ├── vc_cec.h
│   │       ├── vc_cecservice_defs.h
│   │       ├── vc_cecservice.h
│   │       ├── vc_cma.h
│   │       ├── vc_dispmanx.h
│   │       ├── vc_dispmanx_types.h
│   │       ├── vc_dispservice_defs.h
│   │       ├── vc_dispservice_x_defs.h
│   │       ├── vc_gencmd_defs.h
│   │       ├── vcgencmd.h
│   │       ├── vc_hdmi.h
│   │       ├── vc_hdmi_property.h
│   │       ├── vchost.h
│   │       ├── vchost_platform_config.h
│   │       ├── vcilcs_common.h
│   │       ├── vc_ilcs_defs.h
│   │       ├── vcilcs.h
│   │       ├── vc_imageconv_defs.h
│   │       ├── vc_sdtv.h
│   │       ├── vc_service_common.h
│   │       ├── vc_tvservice_defs.h
│   │       ├── vc_tvservice.h
│   │       ├── vc_vchi_audioserv_defs.h
│   │       ├── vc_vchi_bufman_defs.h
│   │       ├── vc_vchi_bufman.h
│   │       ├── vc_vchi_dispmanx.h
│   │       ├── vc_vchi_gencmd.h
│   │       └── vc_vchi_gpuserv.h
│   ├── KHR
│   │   └── khrplatform.h
│   ├── vcinclude
│   │   ├── common.h
│   │   ├── vc_image_types.h
│   │   └── vcore.h
│   ├── VG
│   │   ├── openvg.h
│   │   ├── vgext.h
│   │   ├── vgplatform.h
│   │   └── vgu.h
│   └── WF
│       ├── wfc.h
│       └── wfcplatform.h
├── lib
│   ├── libbcm_host.so
│   ├── libbrcmEGL.so
│   ├── libbrcmGLESv2.so
│   ├── libbrcmOpenVG.so
│   ├── libbrcmWFC.so
│   ├── libcontainers.so
│   ├── libdebug_sym.so
│   ├── libdebug_sym_static.a
│   ├── libdtovl.so
│   ├── libEGL_static.a
│   ├── libelftoolchain.so
│   ├── libGLESv2_static.a
│   ├── libkhrn_client.a
│   ├── libkhrn_static.a
│   ├── libmmal_components.so
│   ├── libmmal_core.so
│   ├── libmmal.so
│   ├── libmmal_util.so
│   ├── libmmal_vc_client.so
│   ├── libopenmaxil.so
│   ├── libvchiq_arm.so
│   ├── libvchostif.a
│   ├── libvcilcs.a
│   ├── libvcos.so
│   ├── libvcsm.so
│   ├── pkgconfig
│   │   ├── bcm_host.pc
│   │   ├── brcmegl.pc
│   │   ├── brcmglesv2.pc
│   │   ├── brcmvg.pc
│   │   ├── mmal.pc
│   │   └── vcsm.pc
│   └── plugins
│       └── plugins
│           ├── reader_asf.so
│           ├── reader_avi.so
│           ├── reader_binary.so
│           ├── reader_flv.so
│           ├── reader_metadata_id3.so
│           ├── reader_mkv.so
│           ├── reader_mp4.so
│           ├── reader_mpga.so
│           ├── reader_ps.so
│           ├── reader_qsynth.so
│           ├── reader_raw_video.so
│           ├── reader_rcv.so
│           ├── reader_rtp.so
│           ├── reader_rtsp.so
│           ├── reader_rv9.so
│           ├── reader_simple.so
│           ├── reader_wav.so
│           ├── writer_asf.so
│           ├── writer_avi.so
│           ├── writer_binary.so
│           ├── writer_dummy.so
│           ├── writer_mp4.so
│           ├── writer_raw_video.so
│           └── writer_simple.so
└── src└── hello_pi├── hello_audio│   ├── audio.c│   ├── audioplay.h│   ├── Makefile│   └── sinewave.c├── hello_dispmanx│   ├── dispmanx.c│   └── Makefile├── hello_encode│   ├── encode.c│   └── Makefile├── hello_fft│   ├── gpu_fft_base.c│   ├── gpu_fft.c│   ├── gpu_fft.h│   ├── gpu_fft_shaders.c│   ├── gpu_fft_trans.c│   ├── gpu_fft_trans.h│   ├── gpu_fft_twiddles.c│   ├── gpu_fft.txt│   ├── hello_fft_2d_bitmap.h│   ├── hello_fft_2d.c│   ├── hello_fft.c│   ├── hex│   │   ├── shader_1024k.hex│   │   ├── shader_128k.hex│   │   ├── shader_16k.hex│   │   ├── shader_1k.hex│   │   ├── shader_2048k.hex│   │   ├── shader_256.hex│   │   ├── shader_256k.hex│   │   ├── shader_2k.hex│   │   ├── shader_32k.hex│   │   ├── shader_4096k.hex│   │   ├── shader_4k.hex│   │   ├── shader_512.hex│   │   ├── shader_512k.hex│   │   ├── shader_64k.hex│   │   ├── shader_8k.hex│   │   └── shader_trans.hex│   ├── mailbox.c│   ├── mailbox.h│   ├── makefile│   └── qasm│       ├── gpu_fft_1024k.qasm│       ├── gpu_fft_128k.qasm│       ├── gpu_fft_16k.qasm│       ├── gpu_fft_1k.qasm│       ├── gpu_fft_2048k.qasm│       ├── gpu_fft_2048k.qinc│       ├── gpu_fft_256k.qasm│       ├── gpu_fft_256.qasm│       ├── gpu_fft_2k.qasm│       ├── gpu_fft_32k.qasm│       ├── gpu_fft_4096k.qasm│       ├── gpu_fft_4k.qasm│       ├── gpu_fft_512k.qasm│       ├── gpu_fft_512.qasm│       ├── gpu_fft_64k.qasm│       ├── gpu_fft_8k.qasm│       ├── gpu_fft_ex.qinc│       ├── gpu_fft.qinc│       └── gpu_fft_trans.qasm├── hello_font│   ├── main.c│   ├── Makefile│   └── Vera.ttf├── hello_jpeg│   ├── jpeg.c│   ├── jpeg.h│   └── Makefile├── hello_mmal_encode│   ├── Makefile│   └── mmal_encode.c├── hello_teapot│   ├── cube_texture_and_coords.h│   ├── Makefile│   ├── models.c│   ├── models.h│   ├── README.md│   ├── teapot.obj.dat│   ├── triangle.c│   ├── triangle.h│   └── video.c├── hello_tiger│   ├── license.txt│   ├── main.c│   ├── Makefile│   ├── readme.txt│   ├── tiger.c│   └── tiger.h├── hello_triangle│   ├── cube_texture_and_coords.h│   ├── Djenne_128_128.raw│   ├── Gaudi_128_128.raw│   ├── Lucca_128_128.raw│   ├── Makefile│   └── triangle.c├── hello_triangle2│   ├── Makefile│   └── triangle2.c├── hello_video│   ├── Makefile│   ├── README│   ├── test.h264│   └── video.c├── hello_videocube│   ├── cube_texture_and_coords.h│   ├── Makefile│   ├── README.md│   ├── triangle.c│   ├── triangle.h│   └── video.c├── hello_world│   ├── Makefile│   └── world.c├── libs│   ├── ilclient│   │   ├── ilclient.c│   │   ├── ilclient.h│   │   ├── ilcore.c│   │   └── Makefile│   ├── revision│   │   ├── Makefile│   │   ├── revision.c│   │   └── revision.h│   └── vgfont│       ├── font.c│       ├── graphics.c│       ├── graphics_x_private.h│       ├── Makefile│       ├── vgfont.h│       ├── vgft.c│       └── vgft.h├── Makefile├── Makefile.include├── README└── rebuild.sh

这些文件博主也不确定是否是系统刷好后就有的,因为中途折腾的时候安装过一些依赖,并且博主的系统自带了FFmpeg程序。常见需要安装的依赖有:libomxil-bellagio-dev等。

sudo apt-get install libomxil-bellagio-dev #在树莓派上安装

②.编写配置脚本

注意:最好不要在这个脚本中添加注释,或者把注释放到最后,续航符号\加上注释有时候会导致命令错误、配置出错。

#!/bin/sh./configure \
--enable-shared \
--disable-static \
--prefix=`pwd`/pi_install \
--extra-cflags=-I/home/boy/opensource/vc/include/IL \
--extra-cflags=-I/home/boy/opensource/x264/pi_install/include \
--extra-ldflags=-L/home/boy/opensource/x264/pi_install/lib \
--extra-ldflags=-L/home/boy/opensource/vc/lib \
--enable-omx \
--enable-omx-rpi \
--enable-encoder=h264_omx \
--enable-libx264 \
--enable-cross-compile \
--cross-prefix=arm-linux-gnueabihf- \
--arch=arm \
--target-os=linux \
--enable-gpl

这几条即为配置omx硬件编码支持的选项:

--enable-omx \
--enable-omx-rpi \
--enable-encoder=h264_omx \

若出现提示缺少头文件等错误:

boy@ubuntu:~/opensource/ffmpeg$ ./pi_config.sh 
ERROR: OpenMAX IL headers from raspberrypi/firmware not found

通过extra-cflags、extra-ldflags添加外部头文件、库文件搜索路径可尝试解决,如下:

--extra-cflags=-I/home/boy/opensource/vc/include/IL \ #复制自树莓派/opt/vc目录,添加OpenMAX IL头文件路径
--extra-cflags=-I/home/boy/opensource/x264/pi_install/include \ #x264头文件路径
--extra-ldflags=-L/home/boy/opensource/x264/pi_install/lib \ #x264库文件路径
--extra-ldflags=-L/home/boy/opensource/vc/lib \ #复制自树莓派/opt/vc目录,omx、mmal等库路径

③.编译、安装

上一步没问题后,就会生成相应的makefile,执行make -j8多线程编译,完成后再make install即可在安装到相应路径:

boy@ubuntu:~/opensource/ffmpeg$ cd pi_install/
boy@ubuntu:~/opensource/ffmpeg/pi_install$ ls
bin  include  lib  share
boy@ubuntu:~/opensource/ffmpeg/pi_install$ 

相应的头文件、库文件添加到应用工程即可编译,在树莓派中调用的时候再添加这些相关的so库到库文件搜索路径即可。

使用硬件编码的程序,后续项目用上再放出来,未完待续~~

编码Demo测试

在doc/example目录下的encode_video.c有完整的FFmpeg的视频编码demo,将yuv420p编码为H264:

/** Copyright (c) 2001 Fabrice Bellard** Permission is hereby granted, free of charge, to any person obtaining a copy* of this software and associated documentation files (the "Software"), to deal* in the Software without restriction, including without limitation the rights* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell* copies of the Software, and to permit persons to whom the Software is* furnished to do so, subject to the following conditions:** The above copyright notice and this permission notice shall be included in* all copies or substantial portions of the Software.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN* THE SOFTWARE.*//*** @file* video encoding with libavcodec API example** @example encode_video.c*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include <libavcodec/avcodec.h>#include <libavutil/opt.h>
#include <libavutil/imgutils.h>static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,FILE *outfile)
{int ret;/* send the frame to the encoder */if (frame)printf("Send frame %3"PRId64"\n", frame->pts);ret = avcodec_send_frame(enc_ctx, frame);if (ret < 0) {fprintf(stderr, "Error sending a frame for encoding\n");exit(1);}while (ret >= 0) {ret = avcodec_receive_packet(enc_ctx, pkt);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)return;else if (ret < 0) {fprintf(stderr, "Error during encoding\n");exit(1);}printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);fwrite(pkt->data, 1, pkt->size, outfile);av_packet_unref(pkt);}
}int main(int argc, char **argv)
{const char *filename, *codec_name;const AVCodec *codec;AVCodecContext *c= NULL;int i, ret, x, y;FILE *f;AVFrame *frame;AVPacket *pkt;uint8_t endcode[] = { 0, 0, 1, 0xb7 };if (argc <= 2) {fprintf(stderr, "Usage: %s <output file> <codec name>\n", argv[0]);exit(0);}filename = argv[1];codec_name = argv[2];/* find the mpeg1video encoder */codec = avcodec_find_encoder_by_name(codec_name);if (!codec) {fprintf(stderr, "Codec '%s' not found\n", codec_name);exit(1);}c = avcodec_alloc_context3(codec);if (!c) {fprintf(stderr, "Could not allocate video codec context\n");exit(1);}pkt = av_packet_alloc();if (!pkt)exit(1);/* put sample parameters */c->bit_rate = 400000;/* resolution must be a multiple of two */c->width = 352;c->height = 288;/* frames per second */c->time_base = (AVRational){1, 25};c->framerate = (AVRational){25, 1};/* emit one intra frame every ten frames* check frame pict_type before passing frame* to encoder, if frame->pict_type is AV_PICTURE_TYPE_I* then gop_size is ignored and the output of encoder* will always be I frame irrespective to gop_size*/c->gop_size = 10;c->max_b_frames = 1;c->pix_fmt = AV_PIX_FMT_YUV420P;if (codec->id == AV_CODEC_ID_H264)av_opt_set(c->priv_data, "preset", "slow", 0);/* open it */ret = avcodec_open2(c, codec, NULL);if (ret < 0) {fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));exit(1);}f = fopen(filename, "wb");if (!f) {fprintf(stderr, "Could not open %s\n", filename);exit(1);}frame = av_frame_alloc();if (!frame) {fprintf(stderr, "Could not allocate video frame\n");exit(1);}frame->format = c->pix_fmt;frame->width  = c->width;frame->height = c->height;ret = av_frame_get_buffer(frame, 0);if (ret < 0) {fprintf(stderr, "Could not allocate the video frame data\n");exit(1);}/* encode 1 second of video */for (i = 0; i < 25; i++) {fflush(stdout);/* Make sure the frame data is writable.On the first round, the frame is fresh from av_frame_get_buffer()and therefore we know it is writable.But on the next rounds, encode() will have calledavcodec_send_frame(), and the codec may have kept a reference tothe frame in its internal structures, that makes the frameunwritable.av_frame_make_writable() checks that and allocates a new bufferfor the frame only if necessary.*/ret = av_frame_make_writable(frame);if (ret < 0)exit(1);/* Prepare a dummy image.In real code, this is where you would have your own logic forfilling the frame. FFmpeg does not care what you put in theframe.*//* Y */for (y = 0; y < c->height; y++) {for (x = 0; x < c->width; x++) {frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;}}/* Cb and Cr */for (y = 0; y < c->height/2; y++) {for (x = 0; x < c->width/2; x++) {frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;}}frame->pts = i;/* encode the image */encode(c, frame, pkt, f);}/* flush the encoder */encode(c, NULL, pkt, f);/* Add sequence end code to have a real MPEG file.It makes only sense because this tiny examples writes packetsdirectly. This is called "elementary stream" and only works for somecodecs. To create a valid file, you usually need to write packetsinto a proper file format or protocol; see muxing.c.*/if (codec->id == AV_CODEC_ID_MPEG1VIDEO || codec->id == AV_CODEC_ID_MPEG2VIDEO)fwrite(endcode, 1, sizeof(endcode), f);fclose(f);avcodec_free_context(&c);av_frame_free(&frame);av_packet_free(&pkt);return 0;
}

简单构建一个工程(基于CMake构建),工程目录如下:

boy@ubuntu:~/encode_test$ ls -l
总用量 20
-rwxrwxr-x  1 boy boy  285 45 23:04 build.sh
-rw-rw-r--  1 boy boy  864 41 23:39 CMakeLists.txt
drwxrwxr-x 10 boy boy 4096 41 23:30 include
drwxrwxr-x  2 boy boy 4096 41 23:31 lib
drwxrwxr-x  2 boy boy 4096 41 23:32 src

lib下即交叉编译生成的相应so库文件,include为对应的头文件,src即为encode_video.c源码,CMake如下:

cmake_minimum_required(VERSION 3.0.0)
# 设置编译工具链
set(GCC "/opt/rpi_tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc")
set(GXX "/opt/rpi_tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-g++")
set(CMAKE_C_COMPLIER ${GCC})
set(CMAKE_CXX_COMPLIER ${GXX})
# 工程名
project(enc_test VERSION 0.1.0)# 设置头文件查找路径
include_directories(${PROJECT_SOURCE_DIR}/include
)
# 查找src目录下的源文件,赋值到SRCS变量
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRCS)
# 设置库文件搜索路径
link_directories("${PROJECT_SOURCE_DIR}/lib"
)
# 生成可执行文件
add_executable(${PROJECT_NAME} ${SRCS})#指定链接库
target_link_libraries(${PROJECT_NAME}avcodecavdeviceavfilteravformatavutilpostprocswresampleswscale
)

cmake生成makefile后,将make得到的可执行文件即可放到树莓派中运行测试。

添加相关so库

将x264和FFmpeg编译生成的库文件放到树莓派的库搜索路径中,然后运行测试:

pi@raspberrypi:~ $ ./enc_test out.h264 libx264

此时就会调用x264编码器,将ffmpeg生成的yuv420p格式的帧转换为h264帧输出到文件out.h264中:

[libx264 @ 0x1e20020] using cpu capabilities: none!
[libx264 @ 0x1e20020] profile High, level 1.3, 4:2:0, 8-bit
Send frame   0
Send frame   1
Send frame   2
Send frame   3
Send frame   4
Send frame   5
Send frame   6
Send frame   7
Send frame   8
Send frame   9
Send frame  10
Send frame  11
Send frame  12
Send frame  13
Send frame  14
Send frame  15
Send frame  16
Send frame  17
Send frame  18
Write packet   0 (size= 2068)
Send frame  19
Write packet   2 (size=  674)
Send frame  20
Write packet   1 (size=  133)
Send frame  21
Write packet   4 (size=  767)
Send frame  22
Write packet   3 (size=  193)
Send frame  23
Write packet   6 (size=  682)
Send frame  24
Write packet   5 (size=  521)
Write packet   8 (size=  868)
Write packet   7 (size=  484)
Write packet   9 (size=  638)
Write packet  10 (size= 2304)
Write packet  12 (size= 1311)
Write packet  11 (size=  829)
Write packet  14 (size=  866)
Write packet  13 (size=  523)
Write packet  16 (size=  831)
Write packet  15 (size=  635)
Write packet  18 (size= 1034)
Write packet  17 (size=  576)
Write packet  19 (size=  682)
Write packet  20 (size= 2477)
Write packet  22 (size= 1415)
Write packet  21 (size=  997)
Write packet  24 (size=  862)
Write packet  23 (size=  878)
[libx264 @ 0x1e20020] frame I:3     Avg QP:24.66  size:  2283
[libx264 @ 0x1e20020] frame P:12    Avg QP:23.14  size:   886
[libx264 @ 0x1e20020] frame B:10    Avg QP:27.26  size:   577
[libx264 @ 0x1e20020] consecutive B-frames: 20.0% 80.0%
[libx264 @ 0x1e20020] mb I  I16..4: 77.3% 12.6% 10.1%
[libx264 @ 0x1e20020] mb P  I16..4: 76.7%  1.1%  0.2%  P16..4: 20.4%  1.2%  0.4%  0.0%  0.0%    skip: 0.0%
[libx264 @ 0x1e20020] mb B  I16..4:  0.0%  0.0%  0.0%  B16..8: 13.9%  0.2%  0.0%  direct:12.4%  skip:73.5%  L0:25.0% L1:57.0% BI:18.1%
[libx264 @ 0x1e20020] final ratefactor: 15.47
[libx264 @ 0x1e20020] 8x8 transform intra:4.2% inter:16.2%
[libx264 @ 0x1e20020] direct mvs  spatial:0.0% temporal:100.0%
[libx264 @ 0x1e20020] coded y,uvDC,uvAC intra: 5.4% 30.6% 4.6% inter: 1.3% 39.8% 9.0%
[libx264 @ 0x1e20020] i16 v,h,dc,p:  0%  0%  0% 100%
[libx264 @ 0x1e20020] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu:  1% 38% 12% 48%  0%  0%  0%  0%  1%
[libx264 @ 0x1e20020] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu:  8%  5% 13% 54%  1%  6%  5%  5%  2%
[libx264 @ 0x1e20020] i8c dc,h,v,p:  1%  7%  5% 87%
[libx264 @ 0x1e20020] Weighted P-Frames: Y:0.0% UV:0.0%
[libx264 @ 0x1e20020] ref P L0: 97.5%  0.6%  1.5%  0.2%  0.1%  0.1%
[libx264 @ 0x1e20020] ref B L0: 60.6% 33.1%  6.2%
[libx264 @ 0x1e20020] kb/s:185.98	

效果

生成H264文件使用VLC播放器播放如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pAAmYzoZ-1666404462192)(resources/f07f1a9831034fdbb4d7d1cf79a75d61.png)]

这篇关于树莓派移植FFmepg记录(x264、硬件编码支持)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/673021

相关文章

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

记录每次更新到仓库 —— Git 学习笔记 10

记录每次更新到仓库 文章目录 文件的状态三个区域检查当前文件状态跟踪新文件取消跟踪(un-tracking)文件重新跟踪(re-tracking)文件暂存已修改文件忽略某些文件查看已暂存和未暂存的修改提交更新跳过暂存区删除文件移动文件参考资料 咱们接着很多天以前的 取得Git仓库 这篇文章继续说。 文件的状态 不管是通过哪种方法,现在我们已经有了一个仓库,并从这个仓

form表单提交编码的问题

浏览器在form提交后,会生成一个HTTP的头部信息"content-type",标准规定其形式为Content-type: application/x-www-form-urlencoded; charset=UTF-8        那么我们如果需要修改编码,不使用默认的,那么可以如下这样操作修改编码,来满足需求: hmtl代码:   <meta http-equiv="Conte

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图

rtmp流媒体编程相关整理2013(crtmpserver,rtmpdump,x264,faac)

转自:http://blog.163.com/zhujiatc@126/blog/static/1834638201392335213119/ 相关资料在线版(不定时更新,其实也不会很多,也许一两个月也不会改) http://www.zhujiatc.esy.es/crtmpserver/index.htm 去年在这进行rtmp相关整理,其实内容早有了,只是整理一下看着方