void media_cut() {
//1.处理一些参数
char* src = "/Users/king/Desktop/ffmpeg/audio/cpptest.mp4";
char* dst = "/Users/king/Desktop/ffmpeg/audio/cut.mp4";;
double startTime = 60.0;
double endTime = 180.0;/// 这里是秒
av_log_set_level(AV_LOG_DEBUG);
//2.打开多媒体文件
int ret = 0;
AVFormatContext *context = NULL;
ret = avformat_open_input(&context, src, NULL, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_DEBUG, "format mmedia = %s\n",av_err2str(ret));
goto __ERROR;
}
//4.打开目的文件的上下文
AVFormatContext *o_context = NULL;
avformat_alloc_output_context2(&o_context, NULL, NULL, dst);
if (!o_context) {
av_log(NULL, AV_LOG_DEBUG, "o_context = null \n");
goto __ERROR;
}
int *stream_map = NULL;
stream_map = av_calloc(context->nb_streams, sizeof(int));
if (stream_map == NULL) {
av_log(NULL, AV_LOG_DEBUG, "stream_map == null\n");
goto __ERROR;
}
int streamIndex = 0;
for (int i = 0; i < context->nb_streams; i++) {
AVStream *outStream = NULL;
AVStream *instream = context->streams[i];
AVCodecParameters *inCodecPar = instream->codecpar;
if (inCodecPar->codec_type != AVMEDIA_TYPE_AUDIO && inCodecPar->codec_type != AVMEDIA_TYPE_VIDEO && inCodecPar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
stream_map[i] = -1;
continue;
}
stream_map[i] = streamIndex++;
outStream = avformat_new_stream(o_context, NULL);
if (!outStream) {
av_log(o_context, AV_LOG_DEBUG, "outStream create failed\n");
goto __ERROR;
}
avcodec_parameters_copy(outStream->codecpar, instream->codecpar);
//codec_tag 设置成0会根据多媒体文件自动适配编解码器 不适特别了解建议写成0 了解的话可以写成一个固定的值
outStream->codecpar->codec_tag = 0;
}
/// 绑定
ret = avio_open2(&o_context->pb, dst, AVIO_FLAG_WRITE, NULL, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_DEBUG, "ret bind = %s\n",av_err2str(ret));
goto __ERROR;
}
//7.写多媒体文件头到目的文件
ret = avformat_write_header(o_context, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_DEBUG, "ret avformat_write_header = %s\n",av_err2str(ret));
goto __ERROR;
}
//8.从源多媒体文件中读到音频/视频/字幕数据到目的文件中
/// 第二个参数-1会选择一个默认的流 第三个参数 就是截取开始的时间戳 第四个参数 对于视频来说并不能从具体时间戳开始而是从最近的I帧处开始
ret = av_seek_frame(context, -1, startTime * AV_TIME_BASE, AVSEEK_FLAG_BACKWARD);
if (ret < 0) {
av_log(NULL, AV_LOG_DEBUG, "seek error = %s\n",av_err2str(ret));
goto __ERROR;
}
/// 初始化时间基 用于后边数据组装时候计算时间基
int64_t *dts_start_time = av_calloc(context->nb_streams, sizeof(int64_t));
for (int i = 0; i < context->nb_streams; i++) {
dts_start_time[i] = -1;
}
int64_t *pts_start_time = av_calloc(context->nb_streams, sizeof(int64_t));
for (int i = 0; i < context->nb_streams; i++) {
pts_start_time[i] = -1;
}
AVPacket pkt;
while (av_read_frame(context, &pkt) >= 0) {
AVStream *instream, *outstream;
if(dts_start_time[pkt.stream_index] == -1 && pkt.dts > 0) {
dts_start_time[pkt.stream_index] = pkt.dts;
}
if (pts_start_time[pkt.stream_index] == -1 && pkt.pts > 0) {
pts_start_time[pkt.stream_index] = pkt.pts;
}
if (stream_map[pkt.stream_index] < 0) {
av_packet_unref(&pkt);
continue;
}
/// 音频的pts和dts都是一样的 对于视频来说 pts时间一定是大于dts时间的
pkt.pts = pkt.pts - pts_start_time[pkt.stream_index];
pkt.dts = pkt.dts - dts_start_time[pkt.stream_index];
// if (pkt.dts > pkt.pts) { 我做实验加上这一句 视频会抖动不顺滑pts (16117453) < dts (16123453) in stream 0
// pkt.pts = pkt.dts;
// }
instream = context->streams[pkt.stream_index];
if (av_q2d(instream->time_base) * pkt.pts > endTime) {
av_log(NULL, AV_LOG_DEBUG, "out of end time\n");
break;
}
pkt.stream_index = stream_map[pkt.stream_index];
outstream = o_context->streams[pkt.stream_index];
av_packet_rescale_ts(&pkt, instream->time_base, outstream->time_base);
pkt.pos = -1;
av_interleaved_write_frame(o_context, &pkt);
av_packet_unref(&pkt);
}
//9.写多媒体文件尾到文件中
av_write_trailer(o_context);
//10.将申请的资源释放掉
__ERROR:
if (context != NULL) {
avformat_close_input(&context);
context = NULL;
}
if (o_context->pb != NULL) {
avio_close(o_context->pb);
}
if (o_context != NULL) {
avformat_free_context(o_context);
o_context = NULL;
}
if (stream_map) {
av_free(stream_map);
}
if (dts_start_time != NULL) {
av_free(dts_start_time);
}
if (pts_start_time != NULL) {
av_free(pts_start_time);
}
}
音视频裁剪demo