FFmpeg实现解封装
2018-08-14 本文已影响212人
PuHJ
一、关键函数介绍:
1、av_register_all()
注册所有的解封装格式,也可以根据不同的封装格式,单个注册。
2、avcodec_register_all()
网络注册,如rtsp和http的
3、打开文件
//AVFormatContext 封装的结构体,创建一个内容为空的指针,内部可以自己管理ic
AVFormatContext *ic = NULL;
int re = avformat_open_input(&ic, path, 0, 0);
根据re的结果可以判断是否成功
4、获取流信息
avformat_find_stream_info(ic, 0)
5、获取音频流信息
//返回的是音频索引
av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0)
6、拖动timestamp时间的frame
/**
* Seek to the keyframe at timestamp.
* 'timestamp' in 'stream_index'.
*
* @param s media file handle
* @param stream_index If stream_index is (-1), a default
* stream is selected, and timestamp is automatically converted
* from AV_TIME_BASE units to the stream specific time_base.
* @param timestamp Timestamp in AVStream.time_base units
* or, if no stream is specified, in AV_TIME_BASE units.
* @param flags flags which select direction and seeking mode
* @return >= 0 on success
*/
av_seek_frame(ic, videoStream, pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);
7、读取下一帧
// 返回值<0代表错误或者读完了
int av_read_frame(AVFormatContext *s, AVPacket *pkt);
二、关键结构体介绍:
1、AVFormatContext
AVIOContext *pb; // I/O context.自定义格式读或者从内存读可用
char filename[1024]; // input or output filename
/**
* Number of elements in AVFormatContext.streams.
*/
unsigned int nb_streams; // 流的数量
/**
* A list of all streams in the file. New streams are created with
* avformat_new_stream().
*
* - demuxing: streams are created by libavformat in avformat_open_input().
* If AVFMTCTX_NOHEADER is set in ctx_flags, then new streams may also
* appear in av_read_frame().
* - muxing: streams are created by the user before avformat_write_header().
*
* Freed by libavformat in avformat_free_context().
*/
AVStream **streams; //音视频字幕流
/**
* Duration of the stream, in AV_TIME_BASE fractional
* seconds. Only set this value if you know none of the individual stream
* durations and also do not set any of them. This is deduced from the
* AVStream values if not set.
*
* Demuxing only, set by libavformat.
*/
int64_t duration; // 获取的总长度(不一定能获取的到,也可通过AVStream获取)
/**
* Total stream bitrate in bit/s, 0 if not
* available. Never set it directly if the file_size and the
* duration are known as FFmpeg can compute it automatically.
*/
int64_t bit_rate; // 比特率,网络适应的时候会用
/**
* Close an opened input AVFormatContext. Free it and all its contents
* and set *s to NULL.
*/
void avformat_close_input(AVFormatContext **s);// 关闭
2、AVStream
/**
* This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented.
*/
AVRational time_base; //时间基数,通过分子分母计算 (double) r.num / (double) r.den
/**
* Decoding: duration of the stream, in stream time base.
* If a source file does not specify a duration, but does specify
* a bitrate, this value will be estimated from bitrate and file size.
*
* Encoding: May be set by the caller before avformat_write_header() to
* provide a hint to the muxer about the estimated duration.
*/
int64_t duration; //换算成秒
int64_t nb_frames; ///< number of frames in this stream if known or 0
3、AVCodecParameters
Codec parameters associated with this stream.
/**
* General type of the encoded data.
*/
enum AVMediaType codec_type; // 标志是否是音频还是视频
/**
* Specific type of the encoded data (the codec used).
*/
enum AVCodecID codec_id; // 对应的编码格式 h264还是其它的
/**
* - video: the pixel format, the value corresponds to enum AVPixelFormat.
* - audio: the sample format, the value corresponds to enum AVSampleFormat.
*/
int format; // 音视频不一样
/**
* Video only. The dimensions of the video frame in pixels.
*/
int width;
int height;
/**
* Audio only. The number of audio channels.
*/
int channels;
/**
* Audio only. The number of audio samples per second.
*/
int sample_rate;
4、AVPacket
/**
* Presentation timestamp in AVStream->time_base units; the time at which
* the decompressed packet will be presented to the user.
* Can be AV_NOPTS_VALUE if it is not stored in the file.
* pts MUST be larger or equal to dts as presentation cannot happen before
* decompression, unless one wants to view hex dumps. Some formats misuse
* the terms dts and pts/cts to mean something different. Such timestamps
* must be converted to true pts/dts before they are stored in AVPacket.
*/
int64_t pts; // 显示时间
/**
* Decompression timestamp in AVStream->time_base units; the time at which
* the packet is decompressed.
* Can be AV_NOPTS_VALUE if it is not stored in the file.
*/
int64_t dts; // 解码时间
uint8_t *data;
int size;
几个重要函数:
AVPacket *pkt = av_packet_alloc(); //创建对象并初始化
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
3、解封装部分代码
//初始化解封装
av_register_all();
//初始化网络
avformat_network_init();
avcodec_register_all();
//打开文件
AVFormatContext *ic = NULL;
//char path[] = "/sdcard/video.flv";
int re = avformat_open_input(&ic, path, 0, 0);
if (re != 0) {
LOGW("avformat_open_input failed!:%s", av_err2str(re));
return;
}
LOGW("avformat_open_input %s success!", path);
//获取流信息
re = avformat_find_stream_info(ic, 0);
if (re != 0) {
LOGW("avformat_find_stream_info failed!");
}
LOGE("duration = %lld nb_streams = %d", ic->duration, ic->nb_streams);
int fps = 0;
int videoStream = 0;
int audioStream = 1;
/**
* 音视频属性打印
*/
for (int i = 0; i < ic->nb_streams; i++) {
AVStream *as = ic->streams[i];
// 视频流
if (as->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
LOGW("视频数据");
videoStream = i;
fps = r2d(as->avg_frame_rate);
LOGW("fps = %d,width=%d height=%d codeid=%d pixformat=%d", fps,
as->codecpar->width,
as->codecpar->height,
as->codecpar->codec_id,
as->codecpar->format
);
//音频流
} else if (as->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
LOGW("音频数据");
audioStream = i;
LOGW("sample_rate=%d channels=%d sample_format=%d",
as->codecpar->sample_rate,
as->codecpar->channels,
as->codecpar->format
);
}
}
// 除了上述中的遍历方法,还可以通过下列av_find_best_stream函数寻找音视频索引
//获取音频流信息
audioStream = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
videoStream = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);;
LOGW("av_find_best_stream audioStream = %d videoStream = %d", audioStream,videoStream);