av_dump_format 会打印出AVFormatContext的内容,打印的内容是什么意思?
我们使用av_dump_format打印出如下信息:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'https://demo.com/BigBuckBunny.mp4':
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: isomavc1mp42
creation_time : 2010-01-10T08:29:06.000000Z
Duration: 00:09:56.47, start: 0.000000, bitrate: 2119 kb/s
Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s (default)
Metadata:
creation_time : 2010-01-10T08:29:06.000000Z
handler_name : (C) 2007 Google Inc. v08.13.2007.
Stream #0:1(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1991 kb/s, 24 fps, 24 tbr, 24k tbn, 48 tbc (default)
Metadata:
creation_time : 2010-01-10T08:29:06.000000Z
handler_name : (C) 2007 Google Inc. v08.13.2007.
"mov,mp4,m4a,3gp,3g2,mj2" 表示输入文件的容器格式(Container Format)支持的扩展名。
在多媒体文件中,容器格式用于组织和存储多个音视频流以及其他相关数据。不同的容器格式支持不同的文件扩展名。这些扩展名用于指示文件的格式和类型。
在示例输出中,"mov,mp4,m4a,3gp,3g2,mj2" 表示输入文件是支持这些扩展名的容器格式。具体含义如下:
"mov":QuickTime Movie 文件,通常用于 macOS 平台。
"mp4":MPEG-4 Part 14 文件,是一种常见的多媒体容器格式,广泛用于存储音视频数据。
"m4a":MPEG-4 Audio 文件,用于存储音频数据。
"3gp":3rd Generation Partnership Project 文件,用于在移动设备上播放音视频。
"3g2":3rd Generation Partnership Project 2 文件,是 3GP 的增强版本。
"mj2":Motion JPEG 2000 文件,用于存储基于 JPEG 2000 压缩的视频。
因此,"mov,mp4,m4a,3gp,3g2,mj2" 表示输入文件是支持这些容器格式的文件,可以根据文件扩展名来推断文件的类型和格式。
多媒体文件格式说法比较笼统,准确说应该是被分为两种格式,编码格式 + 容器格式。
这就相当于我们会用盘子盛菜,也能用盘子盛米饭。
我们可以使用不同的容器格式盛放不同的编码格式。(当然这里也是有一些规定的,某个容器格式允许盛放哪些编码格式都是有明确要求的)
这个容器格式也就是我们日常看到的文件后缀。
在这里的输出中,我们有多个容器格式,说明我们是允许这个网络url下载的内容存放在mov/mp4/m4a等文件格式中的。
在 av_dump_format()
输出的信息中,"Metadata" 部分包含了一些元数据信息,用于描述媒体文件的特定属性和相关数据。下面是对每个字段的解释:
major_brand
:表示文件的主要品牌标识。它表示“最好”基于哪种格式来解析当前的文件。在示例中,"mp42" 表示该文件的主要品牌为 "mp42"。这是一种标识符,用于标识所使用的容器格式或编码器。
minor_version
:表示文件的次要版本号。在示例中,"0" 表示该文件的次要版本为 0。
compatible_brands
:表示文件与哪些兼容的品牌标识符兼容。在示例中,"isomavc1mp42" 表示该文件兼容 "isom"、"avc1" 和 "mp42" 这些品牌标识符。
creation_time
:表示文件的创建时间。在示例中,"2010-01-10T08:29:06.000000Z" 表示该文件的创建时间为 2010 年 1 月 10 日 08:29:06(UTC 时间)。
这些元数据信息提供了关于媒体文件的额外信息,如文件的品牌标识、版本号、兼容性和创建时间。这些信息可以用于判断文件的属性、兼容性和制作信息。
Duration: 00:09:56.47, start: 0.000000, bitrate: 2119 kb/s
这个信息比较好理解,视频文件有9分56秒,播放比特率是2119kb/s
视频的比特率(bitrate)是指在单位时间内传输或处理的比特数,通常以每秒的比特数(bps,bits per second)为单位。它表示视频数据的传输速率或处理速度。
比特率直接影响视频的数据量和质量,较高的比特率意味着更多的数据被分配给每个时间单位,从而提供更高的视频质量和更精细的细节。较低的比特率则表示视频数据被压缩得更多,可以减小文件大小或降低传输带宽要求,但可能会导致视频质量的损失和细节的丢失。
Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s (default)
Metadata:
creation_time : 2010-01-10T08:29:06.000000Z
handler_name : (C) 2007 Google Inc. v08.13.2007.
"Stream #0:0(und)" 表示第一个流(Stream)的信息。下面是对每个字段的解释:
Audio
:表示该流是音频流。
aac (LC)
:表示音频编解码器为 AAC(Advanced Audio Coding)的低复杂度(Low Complexity)模式。
mp4a / 0x6134706D
:表示音频编码器的标识符为 "mp4a",对应的十六进制值为 "0x6134706D"。
44100 Hz
:表示音频采样率为 44,100 Hz,即每秒采集和播放的音频样本数。
stereo
:表示音频通道模式为立体声,即左右两个声道。
fltp
:表示音频采样格式为浮点型(floating point)。
125 kb/s
:表示音频的比特率为 125 kb/s,即每秒传输或处理的音频数据量为 125 kb。
(default)
:表示该流是默认的流。
handler_name
: 表示是由 Google 公司开发的某个版本的处理程序生成或处理的。
"Stream #0:1(und)" 表示第二个流(Stream)的信息,即视频流。下面是对每个字段的解释:
Video
:表示该流是视频流。
h264 (High)
:表示视频编解码器为 H.264(高级)。
avc1 / 0x31637661
:表示视频编码器的标识符为 "avc1",对应的十六进制值为 "0x31637661"。
yuv420p
:表示视频采样格式为 YUV420P,即色彩空间为 YUV,亮度和色度分量的采样比例为 4:2:0。
1280x720
:表示视频分辨率为 1280x720 像素。
[SAR 1:1 DAR 16:9]
:表示视频的样本宽高比(Sample Aspect Ratio)为 1:1,显示宽高比(Display Aspect Ratio)为 16:9。
1991 kb/s
:表示视频的比特率为 1991 kb/s,即每秒传输或处理的视频数据量为 1991 kb。
24 fps
:表示视频的帧率为 24 帧每秒。
24 tbr, 24k tbn, 48 tbc
:表示视频的时间基准信息。
(default)
:表示该流是默认的流。
handler_name
: 表示是由 Google 公司开发的某个版本的处理程序生成或处理的。
AVStream 结构是 FFmpeg 中表示媒体流的数据结构,它包含了媒体流的各种属性和信息。下面是 AVStream 结构中一些常用的成员变量:
index
:表示流的索引号。
id
:表示流的唯一标识符。
codecpar
:指向 AVCodecParameters 结构的指针,包含了与该流关联的编解码器参数。
time_base
:表示流的时间基准,用于将时间单位转换为实际时间。
start_time
:表示流的起始时间。
duration
:表示流的时长。
nb_frames
:表示流中的帧数。
disposition
:表示流的布局或位置相关的标志。
avg_frame_rate
:表示流的平均帧率。
r_frame_rate
:表示流的参考帧率。
metadata
:指向 AVDictionary 结构的指针,包含了流的元数据。
要使用 AVStream 结构,可以先通过 AVFormatContext 结构中的 streams
数组获取特定的 AVStream 结构,然后使用相应的成员变量获取所需的信息。例如,要获取流的索引号可以使用 avStream->index
,获取流的时间基准可以使用 avStream->time_base
,获取流的元数据可以使用 avStream->metadata
。
ffmpeg需要先定位mp4中的视频流,从视频流stream中读取每一帧,将每一帧再转换为yuv格式。
// 解码器
AVCodec* codec = nullptr;
AVCodecContext* codecContext = avcodec_alloc_context3(codec);
// 寻找到视频流
int videoStreamIndex = av_find_best_stream(inputContext, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
if (videoStreamIndex < 0) {
// 没有找到视频流
return -1;
}
// 获取视频流
AVStream* stream = inputContext->streams[videoStreamIndex];
if (avcodec_parameters_to_context(codecContext, stream->codecpar) < 0) {
// 获取解码器上下文失败
return -1;
}
if (avcodec_open2(codecContext, codec, nullptr) < 0) {
// 打开解码器失败
return -1;
}
// 分配视频帧和 YUV 帧
AVFrame* frame = av_frame_alloc();
AVFrame* frameYUV = av_frame_alloc();
int frameBufferSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, codecContext->width, codecContext->height, 1);
uint8_t* frameBuffer = (uint8_t*)av_malloc(frameBufferSize * sizeof(uint8_t));
av_image_fill_arrays(frameYUV->data, frameYUV->linesize, frameBuffer, AV_PIX_FMT_YUV420P, codecContext->width, codecContext->height, 1);
// 初始化图像转换上下文
struct SwsContext* swsContext = sws_getContext(codecContext->width, codecContext->height, codecContext->pix_fmt, codecContext->width, codecContext->height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, nullptr, nullptr, nullptr);
// 读取视频帧并转换为 YUV 格式
AVPacket packet;
while (av_read_frame(inputContext, &packet) >= 0) {
if (packet.stream_index == videoStreamIndex) {
// 解码视频帧
avcodec_send_packet(codecContext, &packet);
avcodec_receive_frame(codecContext, frame);
// 转换为 YUV 格式
sws_scale(swsContext, frame->data, frame->linesize, 0, codecContext->height, frameYUV->data, frameYUV->linesize);
// 在这里可以对 YUV 数据进行处理
// 释放帧的引用
av_frame_unref(frame);
}
av_packet_unref(&packet);
}
使用 av_seek_frame 函数:可以使用 av_seek_frame 函数在特定的时间点进行定位。这个函数可以用于音频和视频流。以下是一个示例代码片段,展示了如何使用 av_seek_frame 定位到指定的时间点:
int64_t timestamp = desired_time * AV_TIME_BASE; // 将秒转换为时间戳
int stream_index = 0; // 假设我们要定位到第一个流
AVStream* stream = formatContext->streams[stream_index];
int64_t seek_target = av_rescale_q(timestamp, AV_TIME_BASE_Q, stream->time_base);
// 定位到指定时间点
av_seek_frame(formatContext, stream_index, seek_target, AVSEEK_FLAG_BACKWARD);
5分钟入门MP4文件格式