0
点赞
收藏
分享

微信扫一扫

FFMPEG SDK软硬解码基础


都有啥

  • 解封装
  • 软硬件解码
  • 像素格式转换
  • 重采样
  • pts/dts
  • 同步策略

FFMPEG解封装

总览

av_register_all()
avformat_network_init()
avformat_open_input(...)
avformat_find_stream_info(...)
av_find_best_stream(...)
AVFormatContext AVStream AVPacket
av_read_frame(...)

avformat_open_input

  • 确保av_register_all avformat_network_init已调用
  • AVFormatContext **ps
  • const char *url
  • AVInputFormat *fmt
  • AVDictionary **options

AVFormatContext

  • AVIOContext *pb; char filename[1024];
  • unsigned int nb_streams;
  • AVStream **streams;
  • int64_6 duration; //AV_TIME_BASE
  • int64_t bit_rate
  • void avformat-close_input(AVFormatContext **s);

avformat_find_stream_info

  • int avformat_find_stream_info(
  • AVFormatContext *ic,
  • AVDictionary **options
  • );
  • flv(没法获取时长) h264 mpeg2

AVStream

  • AVCodecContext *codec; //过时了
  • AVRational time_base;
  • int64_t duration;
  • int64_t nb_frames;
  • AVRational avg_frame_rate;
  • AVCodecParameters *codecpar;(音视频参数)

AVCodecParameters

  • enum AVMediaType codec_type;
  • enum AVCodecID codec_id;
  • uint32_t codec_tag
  • int format
  • int width; int height;
  • uint64_t channel_layout; int channels; int sample_rate; int frame_size;

static double r2d(AVRational r)
{	
	return r.num==0||r.den==0?0:(double)r.num/(double)r.den;
}

av_find_best_stream

  • int av_find_best_stream(
  • AVFormatContext * ic,
  • enum AVMediaType type,
  • int wanted_stream_nb,
  • int related_stream,
  • AVCodec** decoder_ret,
  • int flags
  • )

av_read_frame

  • AVFormatContext *s
  • AVPacket *pkt
  • return 0 if OK, < 0 on error or end of file

AVPacket

  • AVBufferRef *bug
  • int64_t pts; // pts * (num/den)
  • int64_t dts;
  • uint8_t data; int size;
  • AVPacket *av_packet_alloc(void);创建并初始化
  • AVPacket *av_packet_clone(const AVPacket *src); 创建并并用计数
  • int av_packet_ref(AVPacket *dst, const AVpacket *src); av_packet_unref(AVPacket *pkt)
  • void av_packet_free(AVPacket ** pkt); 清空对象并减引用计数
  • void av_init_packet(AVPacket *pkt);默认值
  • int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size);
  • int av_copy_packet(AVPacket *dst, const AVPacket *src); attribute_deprecated

av_seek_frame

  • int av_seek_frame(AVFormatContext *s, int stream_index, // -1 default
  • int 64_t timestampe, //AVStream.time_base
  • int flags);

av_seek_frame flag

  • #define AVSEEK_FLAG_BACKWARD 1 /// < seek backward
  • #define AVSEEK_FLAG_BYTE 2 /// < seeking based on position in bytes
  • #define AVSEEK_FLAG_ANY 3 /// < seeking to any frame, even non-keyframes
  • #define AVSEEK_FLAG_FRAME 4 /// < seeking based on frame number

软硬件解码

avcodec_find_decoder

  • avcodec_register_all();
  • AVCodec *avcodec_find_decoder(enum AVCodecID id);
  • AVCodec *avcodec_find_decoder_by_name(const char *name);
  • avcodec_find_decoder_by_name(“h264_mediacodec”);

AVCodecContext

  • AVCodecContext *avcodec_alloc_context3(const AVCodec * codec)
  • void avcodec_free_context(AVCodecContext **avctx);
  • int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
  • /libavcodec/options_table.h
  • int thread_count;
  • time_base

avcodec_parameters_to_context

  • avcodec_parameters_to_context(codec, p);

AVFrame

  • AVFrame *frame = av_frame_alloc();
  • void av_frame_free(AVFrame **frame);
  • int av_frame_ref(AVFrame *dst, const AVFrame *src);
  • AVFrame *av_frame_clone(const AVFrame *src);
  • void av_frame_unref(AVFrame *frame);
  • uint8_t *data[AV_NUM_DATA_POINTERS];
  • int linesize[AV_NUM_DATA_POINTERS];
  • int width, height; int nb_samples;
  • int64_t pts; int64_t pkt_dts;
  • int sample_rate; uint64_t channel_layout; int. channels;
  • int format; //AVPixelFormat AVSampleFormat

linesize

FFMPEG SDK软硬解码基础_音视频


FFMPEG SDK软硬解码基础_android_02


FFMPEG SDK软硬解码基础_#define_03

avcodec_send_packet

  • int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);

avcodec_receive_frame

  • int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);

重采样和像素格式转换

视频像素和是和尺寸转换

sws_getContext
struct SwsContext *sws_getCachedContext( struct SwsContext *context,
							int srcW, int srcH, enum AVPixelFormat srcFormat,
							int dstW, int dstH, enum AVPixelFormat dstFormat,
							int flags, SwsFilter *srcFilter,
							SwsFilter *dstFilter, const double *param);

int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],
		const int srcStride[], int srcSliceY, int srcSliceH,
		uint8_t *const dst[], const int dstStride[]);
void sws_freeContext(struct SwsContext *swsContext);

  • #define SWS_FAST_BILINEAR 1
  • #define SWS_BILINEAR 2
  • #define SWS_BICUBIC 4
  • #define SWS_X 8
  • #define SWS_POINT 0x10
  • #define SWS_AREA 0x20
  • #define SWS_BICUBLIN 0x40

SwrContext

SwrContext *swr_alloc(void);
SwrContext *swr_alloc_set_opts(
	struct SwrContext *s, int64_t out_ch_layout,
	AVSampleFormat out_sample_fmt, int out_sample_rate,
	int64_t in_ch_layout, AVSampleFormat in_sample_fmt, int in_sample_rate,
	ing log_offset, void *log_ctx);
)
int swr_init(struct SwrContext *s);
void swr_free(struct SwrContext **s);

swr_convert

  • inv swr_convert(struct SwrContext *s, uint8_t **out, int out_count, const uint8_t **in, int in_count);

NDK绘制SurfaceView 3-1

  • cmake android
  • #include <android/native_window.h>
  • Einclude <android/native_window_jni.h>

NDK绘制SurfaceView3-2

  • ANativeWindow *nativeWindow = ANativveWindow_fromSurface(env, surface);
  • // 设置native window的buffer大小,可自动拉伸
  • ANativeWindow_setBuffersGeometry(natie Window, width, height, WINDOW_FORMAT_RGBA_8888);

NDK绘制SurfaceView3-3

  • ANativeWindow_Buffer windowBuffer;
  • ANativeWndow_lock(nativeWindow, &windowBuffer, 0);
  • uint8_t *dst = (uint8_t *)windowBuffer.bits;
  • memcpy(dst, rgb, widthheight4);
  • ANativeWindow_unlockAndPost(nativeWindow);

OpenSL ES

FFMPEG SDK软硬解码基础_封装_04


FFMPEG SDK软硬解码基础_#define_05

初始化引擎

  • //引擎接口
  • SLObjectltf engineObject = NULL;
  • SLEngineItf engineEngine = NULL;
  • slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
  • (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
  • (*engineObject)->GetInterface(engineObjet, SL_IID_ENGINE, &engineEngline);

slCreateEngine

  • SL_AP SLresult SLAPINENTRY slCreateEngine(
  • SLObject ltf *pEngine,
  • SLuint32 numOptions
  • const SLEngineOption * pEngineOptions, //选择项目 默认参数
  • SLuint32 numInterfaces,
  • const SLInterfaceID *pInterfaceIds, //支持的接口
  • const SLboolean * pInterfaceRequired // 接口标识数值,是否支持
  • )

SLObjectltf

  • SLresult(*Realize) (
  • SLObjectltf self,
  • SLboolean async
  • )
  • 对象已实现状态(false阻塞)
  • If SL_BOOLEAN_FALSE, the method will block until termination. Otherwise, the method will return SL_RESULT_SUCCESS, and will be executed asnychronously.

GetInterface

  • SLresult(* GetInterface)(
  • SLObjectltf self,
  • const SLInterfaceId iid,
  • void * pInterface
  • )

创建输出设备

  • SLEnginelft engineEngine = NULL;
  • SLObjectltf outputMixObject = NULL;
  • (*engineEngine)->CreateOutpuMix(engineEngine, &outputMixObject, 0, 0, 0);
  • (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
  • SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
  • SLDataSink audioSnk = {&outputMix, NULL};

配置PCM格式信息

  • SLDataLocator_AndroidSimpleBufferQueue
  • android_queue={SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
  • SLDataFormat_PCM pcm={
  • SL_DATAFORMAT_PCM, //播放pcm格式的数据
  • 2, //2个声道(立体声)
  • SL_SAMPLINGRATE_44_1, //44100hz的频率
  • SL_PCMSAMPLEFORMAT_FIXED_16, //位数16位
  • SL_PCMSAMPLEFORMAT_FIXED_16, //和位数一致就行
  • SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, //立体声(前左后右)
  • SL_BYTEORDER_LITTLEENDIAN //结束标志
  • }
  • SLDataSource slDataSource = {&android_queue, &pcm};

初始化播放器

  • const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
  • const SLboolean req[1] = {SL_BOOLEAN_TRUE};
  • (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slDataSource, &audioSnk, 1, ids, req);
  • // 初始化播放器
  • (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
  • // 得到接口后调用 获取Player接口
  • (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, pcmPlayerPlay);

播放和缓冲队列

  • 注册回调缓冲区 获取缓冲队列接口(*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE, &pcmBufferQueue);
  • (*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack, NULL);
  • (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
  • (*pcmBufferQueue)->Enqueue(pcmBufferQueue, “”, 1);

OpenGL ES 直接绘制YUV

EGL opengles shader glsl

https://www.khronos.org/registry/EGL/sdk/docs/man/ OpenG与窗口系统对应的适配层

FFMPEG SDK软硬解码基础_封装_06

EGL

  • Display 与原生窗口链接
  • EGLDisplay eglGetDisplay
  • EGLBoolean eglInitialize
  • Surface 配置和创建surface(窗口和屏幕上的渲染区域)
  • EGLBoolean eglChooseConfig
  • GELSurface eglCreateWindowSurface
  • Context创建渲染环境(Context上下文)
  • 渲染环境指OpenGL ES的所有项目运行需要的数据结构。如顶点、片段着色器、顶点数据矩阵
  • eglCreateContext
  • eglMakeCurrent

着色器语言GLSL

  • 顶点着色器是针对每个顶点执行一次,用于确定顶点的位置;片元着色器是针对每个片元(可以理解为每个像素)执行一次,用于确定每个片元(像素)的颜色
  • GLSL的基本语法与C基本相同
  • 它完美的支持向量和矩阵操作
  • GLSL提供了大量的内置函数来提供丰富的扩展功能
  • 它是通过限定符操作来管理输入输出类型的

显示yuv代码演示

ffmpeg -i 720.mp4 -pix_fmt yuv420p -s 424x240 out.yuv
使用shader显示准备好的yuv数据
封装EGL和shader

顶点着色器

FFMPEG SDK软硬解码基础_封装_07


FFMPEG SDK软硬解码基础_android_08

顶点信息

FFMPEG SDK软硬解码基础_封装_09

YUV转RGB

  • R = Y + 1.402 (Cr - 128)
  • G = Y - 0.34414 (Cb-128) - 0.71414(Cr - 128)
  • B = Y + 1.772(Cb - 128)
  • ( 1.0, 1.0, 1.0,
  • 0.0, -0.39465, 2.03211,
  • 1.13983, -0.58060, 0.0 )

glTextParameteri

  • glTextParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  • glTextParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  • GL_TEXTURE_MIN_FILTE: 缩小过滤
  • GL_TEXTURE_MAG_FILTER: 放大过滤
  • GL_LINEAR: 线性过滤,使用距离当前渲染像素中心最近的4个纹素加权平均值.

pts/dts

同步策略

项目实战

项目用到的设计模式

  • Adapter适配器模式:封装ffmpeg、opengl、opensl
  • Builder构建者模式:构建播放器对象
  • Proxy代理模式:管理播放器创建和线程安全
  • Facade外观(门面)模式:播放器管理解封装、解码、重采样、显示、音频播放
  • Singleton单例模式:唯一的构建者对象
  • 生产者消费者模式:解封模块生产数据包,解码模块消费解码
  • Observer观察者模式:模块间通信

播放媒体文件的顺序图

FFMPEG SDK软硬解码基础_音视频_10


举报

相关推荐

0 条评论