1.日志系统
常用的日志级别:
- AV_LOG_ERROR
- AV_LOG_WARNING
- AV_LOG_INFO
- AV_LOG_DEBUG
#include <stdio.h>
#include <libavutil/log.h>int main(int argc, char *argv[])
{av_log_set_level(AV_LOG_DEBUG);av_log(NULL, AV_LOG_DEBUG, "hello world!\n");return 0;
}
2.文件的删除与重命名
文件删除与重命名的API:
- avpriv_io_delete()
- avpriv_io_move()
int ret;// 重命名ret = avpriv_io_move("111.txt", "222.txt");if(ret < 0) {av_log(NULL, AV_LOG_ERROR, "Failed to rename\n");return -1;}av_log(NULL, AV_LOG_INFO, "Success to renmae\n");// 删除ret = avpriv_io_delete("./test.txt");if(ret < 0) {av_log(NULL, AV_LOG_ERROR, "Failed to delete\n");return -1;}av_log(NULL, AV_LOG_INFO, "Success to delete\n");
3.目录操作
操作目录重要函数:
- avio_open_dir()
- avio_read_dir()
- avio_close_dir()
操作目录重要结构体:
- AVIODirContext
- AVIODirEntry
avdevice_register_all();int ret;AVIODirContext *ctx = NULL;AVIODirEntry *entry = NULL;av_log_set_level(AV_LOG_INFO);ret = avio_open_dir(&ctx, "./", NULL);if(ret < 0){av_log(NULL, AV_LOG_ERROR, "Can't open dir: %s\n", av_err2str(ret));return -1;}while(1) {avio_read_dir(ctx, &entry);if(ret < 0){av_log(NULL, AV_LOG_ERROR, "Can't read dir: %s\n", av_err2str(ret));goto __fail;}if(!entry) {break;}av_log(NULL, AV_LOG_INFO,"%-9s %12"PRId64" %s\n", entry->size, entry->name);avio_free_directory_entry(&entry);}__fail:avio_close_dir(&ctx);
4.抽取音频数据
- 1.处理一些参数
- 2.打开多媒体文件
- 3.从多媒体文件中找到音频流
- 4.打开目的文件的上下文
- 5.为目的文件,创建一个新的音频流
- 6.设置输出音频参数
- 7.写多媒体文件头到目的文件
- 8…从源多媒体文件中读音频数据到目的文件中
- 9.写多媒体文件尾到文件中
- 10.将申请的资源释放掉
步骤比较多,一点一点来实现:
// 1.处理一些参数if(argc < 3) {av_log(NULL, AV_LOG_INFO, "argument must be 3");exit(-1);}src = argv[1];dst = argv[2];// 2.打开多媒体文件ret = avformat_open_input(&pFmtCtx, src, NULL, NULL);if(ret < 0) {av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret));exit(-1);}
// 3.从多媒体文件中找到音频流idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);if(idx < 0) {av_log(pFmtCtx, AV_LOG_ERROR, "Does not include audio\n");goto _ERROR;}// 4.打开目的文件的上下文oFmtCtx = avformat_alloc_context();if(!oFmtCtx) {av_log(NULL, AV_LOG_ERROR, "No Memory\n");goto _ERROR;}outFmt = av_guess_format(NULL, dst, NULL);oFmtCtx->oformat = outFmt;// 5.为目的文件,创建一个新的音频流outStream = av_format_new_stream(oFmtCtx, NULL);// 6.设置输出音频参数inStream = pFmtCtx->stream[idx];avcodec_parameters_copy(outStream->codecpar, inStream->codecpar);outStream->codecpar->codec_tag = 0;
// 7.写多媒体文件头到目的文件ret = avformat_write_header(oFmtCtx, NULL);if(ret < 0) {av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret));goto _ERROR;}// 8.聪源多媒体文件中读到音频数据到目的文件中while(av_read_frame(pFmtCtx, &pkt) >= 0) {if(pkt.stream_index == idx) {pkt.pts = av_rescale_q_rnd(pkt.pts, inStream->time_base, outStream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);pkt.dts = pkt.dts;pkt.duration = av_rescale_q(pkt.duration, inStream->time_base, outStream->time_base);pkt.stream_index = 0;pkt.pos = -1;av_interleaved_write_frame(oFmtCtx, &pkt);av_packet_unref(&pkt);}}// 9.写多媒体文件尾到文件中av_write_trailer(oFmtCtx);// 10.将申请的资源释放掉
_ERROR:if(pFmtCtx) {avformat_close_input(&pFmtCtx);pFmtCtx = NULL;}if(oFmtCtx->pb) {avio_close(oFmtCtx->pb);}if(oFmtCtx) {avformat_free_context(oFmtCtx);oFmtCtx = NULL;}
6.抽取视频数据
与处理音频流程相同,简单修改即可
// 3.从多媒体文件中找到视频流idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);if(idx < 0) {av_log(pFmtCtx, AV_LOG_ERROR, "Does not include VIDEO\n");goto _ERROR;}... ...// 8.从源多媒体文件中读到视频数据到目的文件中while(av_read_frame(pFmtCtx, &pkt) >= 0) {if(pkt.stream_index == idx) {pkt.pts = av_rescale_q_rnd(pkt.pts, inStream->time_base, outStream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);pkt.dts = av_rescale_q_rnd(pkt.dts, inStream->time_base, outStream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);// pkt.dts = pkt.dts;pkt.duration = av_rescale_q(pkt.duration, inStream->time_base, outStream->time_base);pkt.stream_index = 0;pkt.pos = -1;av_interleaved_write_frame(oFmtCtx, &pkt);av_packet_unref(&pkt);}}
6.多媒体格式转封装
7.视频裁剪
程序是在上面的程序基础上修改的,这里就把核心修改地方贴出来。
有两个注意点:(对应下面的修改2和修改3)
第一个是音视频时间的问题。
针对音频:从第5秒钟截取,那他就是第5秒。针对视频:因为有IPB 帧,如果刚好第5秒是P帧或者B帧,没有了I帧,那么就不能解码成功,播放的时候就会花屏。
解决:告诉ffmpeg如果不是I帧,就要向前或者向后找最近的I帧
第二个是时间的问题。
由于是裁剪,所以需要计算相对时间。 使用后面的时间减去第一个时间基的时间,这样子才能保证时间的正确性。音频的dts和pts是相同的,而视频可能是不同的,所以这里需要多加一步判断。