容器格式
视频容器格式是一种封装格式,用于存储在单一文件中的多种类型的数据,这通常包括视频和音频轨道、元数据(比如标题、作者等信息)、字幕和其他可能的数据流。容器格式定义了如何封装这些数据,但它不定义这些数据的编码方式。编码由视频和音频编解码器决定,而容器格式负责存储编码后的数据和同步信息,确保视频和音频的播放同步。
常见的视频容器格式包括:
- AVI (Audio Video Interleave):由微软开发的早期视频容器格式,兼容性良好,但对于现代编码格式的支持有限。
- MP4 (MPEG-4 Part 14):目前最流行的视频容器格式之一,支持各种视频和音频编码,包括H.264和AAC,适用于网络传输和流媒体。
- MKV (Matroska Video):一个开源格式,支持存储几乎所有现代视频和音频编码,以及多语言字幕和丰富的元数据,非常适合存储高清影片。
- MOV (QuickTime File Format):由苹果公司开发,原本是QuickTime播放器的默认格式,支持复杂的视频编辑特性,如多轨音频和文字。
- FLV (Flash Video):曾经是互联网视频共享的主流格式,主要用于Adobe Flash Player内的视频播放,随着HTML5和其他技术的兴起,其流行度已大大减少。
容器格式的选择取决于使用场景、兼容性需求和特定功能(如支持章节、字幕等)。由于容器仅封装数据,并不影响数据本身的质量,因此理论上,相同编码和质量的视频,不论封装在哪种容器中,播放效果应该是一致的。
以下是简单的视频格式转换的操作:
转换步骤 基于pyav
1.打开输入容器(也就是需要被转化的源视频文件)
2.打开输出容器(转换后输出的文件),一般伴随open,不存在的输出文件会被创建。比如pyav(封装了ffmpeg的python包)
` # 打开输入容器
input_container = av.open(input_path, format=input_format)
# 打开输出容器并设置格式
output_container = av.open(output_path + "\\" + out_file_name + '.' + output_format, 'w',
format=output_format)`
3.检查输入容器中存在的流,为输出容器对应添加(你需要转换的格式)。比如说mp4视频,其中有一个音频流采用aac编解码器,你需要转换的容器格式是avi,它不支持aac,而是支持ac3,那么输出容器需要的就是ac3编解码器的音频流
if input_container.streams.audio: audio_stream = output_container.add_stream(codec_name_audio)
4.解析数据和转换编码:视频一般都会含有基本的音频流和视频流,有的还有字幕流等。这些流都被封装在一个视频容器中,也就是常说的mp4,mkv类型的容器,不同的容器格式对应了不同的编解码器。要做到转换视频格式(容器格式),首先要做的就是将压缩数据解析成原始数据。由于是多个流封装,所以第一步是将其解复用,将所有的流拿出来单独出来。
for packet in input_container.demux():#这里第一步是做的解复用,解析出容器中所有的流 if packet.stream.type == 'video': for frame in packet.decode():#解码流,返回的是一个迭代器,遍历流的所有帧 frame.pts = None # 清除时间戳,强制重新计算 for encoded_packet in video_stream.encode(frame):#使用输出容器的流即将其重新编码 output_container.mux(encoded_packet)#将数据封装到输出容器 logger.info(frame.index) elif packet.stream.type == 'audio' and 'audio_stream' in locals(): for frame in packet.decode(): frame.pts = None for encoded_packet in audio_stream.encode(frame): output_container.mux(encoded_packet) # wx.CallAfter(dialog.m_gauge1.UpdateProgress, i) elif packet.stream.type == 'subtitles' and 'subtitle_stream' in locals(): for frame in packet.decode(): frame.pts = None encoded_packet = subtitle_stream.encode(frame) output_container.mux(encoded_packet) # wx.CallAfter(dialog.m_gauge1.UpdateProgress, i)
5.关闭容器
input_container.close()
output_container.close()
注意:因为没有细致的处理,所以可能有一些警告信息