参考链接:
本次移植为FFmpeg添加了x264软件编码器、Omx-rpi硬件编码的支持
进入源码目录,根据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.pc
4 directories, 6 files
boy@ubuntu:~/opensource/x264/pi_install$
可以看到已经根据我们的configure配置项,生成了so动态库、可执行文件等。
源码下载链接: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.txt
18 directories, 229 files
编译完成即可拷贝头文件、库文件到自己的工程目录,编写相关应用程序。
libx264是使用CPU进行编码转换的,即软件编码,运行起来CPU占用率非常高。为了降低CPU占用率,决定使用硬件加速编码。
首先,需要知道两个比较关键的东西:
PS:博主只用到编码,因此只添加硬件编码支持,硬件解码的添加应该大同小异,有空再折腾。
树莓派交叉编译添加硬件编码支持的资料非常少,折腾了非常久( ~ . ~痛苦面具),最后在某歌搜索到一个比较有用的博客:为树莓派交叉编译FFMPEG工具 | Sunrise 博客 (yjdwbj.github.io)
根据该博客的指导,在树莓派/opt/vc目录下包含有omx、mmal相关的库文件、头文件以及相关的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库到库文件搜索路径即可。
使用硬件编码的程序,后续项目用上再放出来,未完待续~~
在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
#include
#include
#include
#include
#include
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 , 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 called
avcodec_send_frame(), and the codec may have kept a reference to
the frame in its internal structures, that makes the frame
unwritable.
av_frame_make_writable() checks that and allocates a new buffer
for 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 for
filling the frame. FFmpeg does not care what you put in the
frame.
*/
/* 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 packets
directly. This is called "elementary stream" and only works for some
codecs. To create a valid file, you usually need to write packets
into 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 4月 5 23:04 build.sh
-rw-rw-r-- 1 boy boy 864 4月 1 23:39 CMakeLists.txt
drwxrwxr-x 10 boy boy 4096 4月 1 23:30 include
drwxrwxr-x 2 boy boy 4096 4月 1 23:31 lib
drwxrwxr-x 2 boy boy 4096 4月 1 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}
avcodec
avdevice
avfilter
avformat
avutil
postproc
swresample
swscale
)
cmake生成makefile后,将make得到的可执行文件即可放到树莓派中运行测试。
将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播放器播放如下: