一、MP4提取H265裸流无效
FFmpeg解封装得到的AVPacket只包含了视频压缩数据,没有相关的参数集信息(比如:h265的vps头信息,h264的sps、pps头信息,AAC的adts头信息),不能初始化解码器。
二、添加头信息
StartCodePrefix的两种方式: Annex B和HVCC。
- Annex B:在NALU前加0x000001或者0x00000001 ;
- HVCC:在NALU前加上指示其长度的前缀。
MP4编码方式,Nalu开始四个字节表示数据长度。在FFmpeg中,这些头信息(VPS、SPS、PPS)是保存在解码器上下文(AVCodecContext)的extradata中的,所以我们需要为每一种格式的视频添加相应的解码头信息,这样解码器(MediaCodec)才能正确解析每一个AVPacket里的视频数据。FFmpeg提供了AVBitStreamFilter类实现头信息添加的功能。
三、音视频分离步骤
- 获取AVPacket
av_read_frame(fmt_ctx, &pkt)
- 添加头信息
if (av_bsf_send_packet(bsf_ctx, &pkt) < 0) {
std::cerr << "failed to push" << std::endl;
exit(1);
}
while (av_bsf_receive_packet(bsf_ctx, &pkt) == 0);
1、简单版本(不支持音频AAC)
#include <iostream>
#include <string>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#ifdef __cplusplus
}
#endif // __cplusplus
int demux(std::string mediafile) {
const AVBitStreamFilter *filter = NULL;
AVFormatContext *fmt_ctx = NULL;
AVBSFContext *bsf_ctx;
AVPacket pkt;
AVStream* videostream = NULL;
AVStream* audiostream = NULL;
AVCodecID video_codec_id;
AVCodecID audio_codec_id;
FILE *fp_vides = NULL, *fp_audes = NULL;
int i, vid_idx, aud_idx;
std::string videofile;
std::string audiofile;
if (avformat_open_input(&fmt_ctx, mediafile.c_str(), NULL, NULL) != 0) {
av_log(NULL, AV_LOG_ERROR, "Could not open input file");
exit(1);
}
av_dump_format(fmt_ctx, 0, mediafile.c_str(), 0);
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
avformat_free_context(fmt_ctx);
av_log(NULL, AV_LOG_ERROR, "Failed to retrieve input stream information");
exit(1);
}
for (i = 0; i<fmt_ctx->nb_streams; i++)
{
//vidoe
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
vid_idx = i;
videostream = fmt_ctx->streams[vid_idx];
video_codec_id = videostream->codecpar->codec_id;
}
//audio
else if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
aud_idx = i;
audiostream = fmt_ctx->streams[aud_idx];
audio_codec_id = audiostream->codecpar->codec_id;
}
//such as subtitile
else {
//To DO
}
}
if (videostream) {
switch (video_codec_id) {
case AV_CODEC_ID_H264:
filter = av_bsf_get_by_name("h264_mp4toannexb");
videofile = "video_es.h264";
break;
case AV_CODEC_ID_HEVC:
filter = av_bsf_get_by_name("hevc_mp4toannexb");
videofile = "video_es.h265";
break;
default:
av_log(NULL, AV_LOG_ERROR, "Unkonw Video AVCodecID");
exit(1);
}
fp_vides = fopen(videofile.c_str(), "wb");
if (!fp_vides) {
std::cerr << "Could not open file" << videofile.c_str() << std::endl;
exit(