接着上文继续开车,https://www.jianshu.com/p/6e3163a6805b,体会vi打码的酸爽!!!
6视频的裁剪
#include <libavformat/avformat.h>
#include <libavutil/log.h>
#include <libavutil/timestamp.h>
#include <stdlib.h>
//implicit declaration of function 'atio'
static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag)
{
AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
tag,
av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
pkt->stream_index);
}
int tailoring_Video(double from_seconds,double end_seconds,const char *in_filename,const char *out_filename){
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
AVOutputFormat *ofmt = NULL;
AVPacket pkt;
int ret,i;
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
av_register_all();
#endif
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
avcodec_register_all();
#endif
ret = avformat_open_input(&ifmt_ctx,in_filename,0,0);
if(ret < 0){
av_log(NULL,AV_LOG_ERROR,"不能打开%s\n",in_filename);
goto fail;
}
ret = avformat_find_stream_info(ifmt_ctx,0);
if(ret < 0){
av_log(NULL,AV_LOG_ERROR,"没有发现输入文件流\n");
goto fail;
}
av_dump_format(ifmt_ctx,0,in_filename,0);
// 输出文件上下文
avformat_alloc_output_context2(&ofmt_ctx,NULL,NULL,out_filename);
if(!ofmt_ctx){
av_log(NULL,AV_LOG_ERROR,"输出音频文件上下文创建失败\n");
ret = AVERROR_UNKNOWN;
goto fail;
}
ofmt = ofmt_ctx ->oformat;
for(int i = 0; i < ifmt_ctx->nb_streams;i++){
//拷贝流
// // 在内存中拷贝一份多媒体文件
AVStream *in_stream = ifmt_ctx ->streams[i];
AVStream *out_stream = avformat_new_stream(ofmt_ctx,in_stream->codec->codec);
if(!out_stream){
av_log(NULL,AV_LOG_ERROR,"错误的输出流信息\n");
ret = AVERROR_UNKNOWN;
goto fail;
}
// 拷贝codec
ret = avcodec_copy_context(out_stream->codec,in_stream->codec);
if(ret < 0){
av_log(NULL,AV_LOG_ERROR,"音视频流上下文拷贝失败\n ");
ret = AVERROR_UNKNOWN;
goto fail;
}
out_stream->codec->codec_tag = 0;
if(ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER){
out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
}
av_dump_format(ofmt_ctx,0,out_filename,1);
if(!(ofmt->flags & AVFMT_NOFILE)){
ret = avio_open(&ofmt_ctx->pb,out_filename,AVIO_FLAG_WRITE);
if(ret < 0){
av_log(NULL,AV_LOG_ERROR,"打开输出文件%s失败\n",out_filename);
goto fail;
}
}
// 多媒体头
ret = avformat_write_header(ofmt_ctx,NULL);
if(ret < 0){
av_log(NULL,AV_LOG_ERROR,"打开输出文件发生错误%s\n",av_err2str(ret));
goto fail;
}
// 截取一段时间,相当于拖一段时间
ret = av_seek_frame(ifmt_ctx,-1,from_seconds * AV_TIME_BASE,AVSEEK_FLAG_ANY);
if(ret < 0){
av_log(NULL,AV_LOG_ERROR,"错误seek\n");
goto fail;
}
int64_t *dstStartFrom = malloc(sizeof(int64_t) * ifmt_ctx ->nb_streams);
//向内存区域填充特定的值
memset(dstStartFrom,0,sizeof(int64_t)*ifmt_ctx->nb_streams);
int64_t *ptsStartFrom = malloc(sizeof(int64_t) *ifmt_ctx->nb_streams);
memset(ptsStartFrom,0,sizeof(int64_t) * ifmt_ctx->nb_streams);
while(1){
AVStream *in_stream,*out_stream;
// 读取的是压缩包
ret = av_read_frame(ifmt_ctx,&pkt);
if(ret < 0)break;
in_stream = ifmt_ctx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];
log_packet(ifmt_ctx,&pkt,"in");
// 时间戳的比较 超过结尾时间 就跳槽循环
if(av_q2d(in_stream->time_base) * pkt.pts > end_seconds){
av_free_packet(&pkt);
break;
}
if(dstStartFrom[pkt.stream_index]== 0){
dstStartFrom[pkt.stream_index] = pkt.dts;
printf("dstStartFrom:%s\n",av_ts2str(dstStartFrom[pkt.stream_index]));
}
if(ptsStartFrom[pkt.stream_index]== 0){
ptsStartFrom[pkt.stream_index] = pkt.pts;
printf("ptsStartFrom:%s\n",av_ts2str(ptsStartFrom[pkt.stream_index]) );
}
//改变时间基并拷贝包
// [mp4 @ 0x7ff8f7008200] pts (14448) < dts (18060) in stream 0
pkt.pts = av_rescale_q_rnd(pkt.pts - ptsStartFrom[pkt.stream_index],in_stream->time_base,out_stream->time_base,AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
pkt.dts = av_rescale_q_rnd(pkt.dts - dstStartFrom[pkt.stream_index],in_stream->time_base,out_stream->time_base,AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
if(pkt.pts < 0){
pkt.pts = 0;
}
if(pkt.dts < 0){
pkt.dts = 0;
}
if(pkt.pts < pkt.dts) continue;
pkt.duration = (int)av_rescale_q((int64_t)pkt.duration,in_stream->time_base,out_stream->time_base);
pkt.pos = -1;
log_packet(ofmt_ctx,&pkt,"out");
ret = av_interleaved_write_frame(ofmt_ctx,&pkt);
if(ret < 0){
av_log(NULL,AV_LOG_ERROR,"错误的包\n");
break;
}
av_free_packet(&pkt);
}
free(dstStartFrom);
free(ptsStartFrom);
av_write_trailer(ofmt_ctx);
fail:
avformat_close_input(&ifmt_ctx);
if(ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
// Segmentation fault: 11
avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
if(ret < 0 && ret != AVERROR_EOF){
av_log(NULL,AV_LOG_ERROR,"发送未知错误:%s",av_err2str(ret));
return -1;
}
return 0;
}
int main(int argc ,char *argv[]){
av_log_set_level(AV_LOG_INFO);
if(argc < 5){
av_log(NULL,AV_LOG_ERROR,"缺少参数!!!");
return -1;
}
double startTime = atoi(argv[1]);
double endTime = atoi(argv[2]);
tailoring_Video(startTime,endTime,argv[3],argv[4]);
return 0;
}
编译可以通过,但有多出警告!!! 运行错误,没有找到问题,欢迎大佬指正!!!
image.png
运行结果:
image.png
pts (0) < dts (3600) in stream 0错误的包
在while(1)循环加if(pkt.pts < pkt.dts) continue;
播放这个裁剪视频会有一些报错
illegal short term buffer state detected [h264 @ 0x7f89100da200] Missing reference picture, default is 0
[h264 @ 0x7f89100da200] decode_slice_header error
[h264 @ 0x7f8910054800] Missing reference picture, default is 0
[h264 @ 0x7f8910054800] decode_slice_header error
[h264 @ 0x7f8910054e00] reference picture missing during reorder
Last message repeated 4 times
[h264 @ 0x7f8910054e00] Missing reference picture, default is 0
[h264 @ 0x7f8910054e00] decode_slice_header error
7 iOS实战演练一
实现功能:有个两个音视频文件,抽取其中一个的音频流和另个一个视频的视频流,进行合并成一个音视频文件,还需要裁减 .
实际应用就是音视频App小咖秀功能.
网友评论