如何使用c++ ffmpeg 进行视频mkv转mp4
时间: 2024-06-08 21:07:48 浏览: 190
使用ffmpeg进行视频格式转换
要使用 C++ 和 FFmpeg 进行视频格式转换,你需要了解 FFmpeg 的基本用法和 C++ 的编程知识。
以下是一个简单的示例代码,可以将 MKV 格式的视频文件转换为 MP4 格式。在代码中,我们使用了 FFmpeg 提供的 libavformat 和 libavcodec 库来进行视频格式的解封装和编码。
```c++
#include <iostream>
#include <string>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
}
int main(int argc, char* argv[]) {
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " input.mkv output.mp4" << std::endl;
return 1;
}
const std::string input_filename = argv[1];
const std::string output_filename = argv[2];
// 初始化 FFmpeg
av_register_all();
// 打开输入文件
AVFormatContext* input_format_context = nullptr;
if (avformat_open_input(&input_format_context, input_filename.c_str(), nullptr, nullptr) < 0) {
std::cerr << "Could not open input file: " << input_filename << std::endl;
return 1;
}
// 获取流信息
if (avformat_find_stream_info(input_format_context, nullptr) < 0) {
std::cerr << "Could not find stream information" << std::endl;
avformat_close_input(&input_format_context);
return 1;
}
// 找到视频流
int video_stream_index = -1;
for (unsigned int i = 0; i < input_format_context->nb_streams; i++) {
AVStream* stream = input_format_context->streams[i];
if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_index = i;
break;
}
}
if (video_stream_index == -1) {
std::cerr << "Could not find video stream" << std::endl;
avformat_close_input(&input_format_context);
return 1;
}
// 打开编码器
AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec) {
std::cerr << "Could not find H.264 codec" << std::endl;
avformat_close_input(&input_format_context);
return 1;
}
AVCodecContext* codec_context = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codec_context, input_format_context->streams[video_stream_index]->codecpar);
if (avcodec_open2(codec_context, codec, nullptr) < 0) {
std::cerr << "Could not open codec" << std::endl;
avcodec_free_context(&codec_context);
avformat_close_input(&input_format_context);
return 1;
}
// 创建输出文件
AVFormatContext* output_format_context = nullptr;
if (avformat_alloc_output_context2(&output_format_context, nullptr, "mp4", nullptr) < 0) {
std::cerr << "Could not create output context" << std::endl;
avcodec_free_context(&codec_context);
avformat_close_input(&input_format_context);
return 1;
}
// 添加视频流
AVStream* output_stream = avformat_new_stream(output_format_context, codec);
if (!output_stream) {
std::cerr << "Could not create output stream" << std::endl;
avcodec_free_context(&codec_context);
avformat_close_input(&input_format_context);
avformat_free_context(output_format_context);
return 1;
}
output_stream->id = output_format_context->nb_streams - 1;
if (avcodec_parameters_copy(output_stream->codecpar, input_format_context->streams[video_stream_index]->codecpar) < 0) {
std::cerr << "Could not copy codec parameters" << std::endl;
avcodec_free_context(&codec_context);
avformat_close_input(&input_format_context);
avformat_free_context(output_format_context);
return 1;
}
// 打开输出文件
if (!(output_format_context->oformat->flags & AVFMT_NOFILE)) {
if (avio_open(&output_format_context->pb, output_filename.c_str(), AVIO_FLAG_WRITE) < 0) {
std::cerr << "Could not open output file: " << output_filename << std::endl;
avcodec_free_context(&codec_context);
avformat_close_input(&input_format_context);
avformat_free_context(output_format_context);
return 1;
}
}
// 写入头部信息
if (avformat_write_header(output_format_context, nullptr) < 0) {
std::cerr << "Error occurred when writing header" << std::endl;
avcodec_free_context(&codec_context);
avformat_close_input(&input_format_context);
avformat_free_context(output_format_context);
return 1;
}
// 转换数据
AVPacket packet;
av_init_packet(&packet);
while (true) {
AVStream* stream = input_format_context->streams[video_stream_index];
if (av_read_frame(input_format_context, &packet) < 0) {
break;
}
if (packet.stream_index != video_stream_index) {
av_packet_unref(&packet);
continue;
}
packet.stream_index = output_stream->index;
AVFrame* frame = av_frame_alloc();
if (!frame) {
std::cerr << "Could not allocate frame" << std::endl;
av_packet_unref(&packet);
break;
}
int ret = avcodec_send_packet(codec_context, &packet);
if (ret < 0) {
std::cerr << "Error sending packet to codec" << std::endl;
av_frame_free(&frame);
av_packet_unref(&packet);
break;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codec_context, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
av_frame_free(&frame);
break;
} else if (ret < 0) {
std::cerr << "Error during decoding" << std::endl;
av_frame_free(&frame);
break;
}
if (avcodec_send_frame(codec_context, frame) < 0) {
std::cerr << "Error sending frame to codec" << std::endl;
av_frame_free(&frame);
break;
}
while (avcodec_receive_packet(codec_context, &packet) == 0) {
packet.stream_index = output_stream->index;
av_write_frame(output_format_context, &packet);
av_packet_unref(&packet);
}
av_frame_free(&frame);
}
av_packet_unref(&packet);
}
// 写入尾部信息
av_write_trailer(output_format_context);
// 释放资源
avcodec_free_context(&codec_context);
avformat_close_input(&input_format_context);
avformat_free_context(output_format_context);
return 0;
}
```
该示例代码中,我们从命令行获取输入和输出文件的名字,然后使用 FFmpeg 解析输入文件并找到视频流。接着,我们打开 H.264 编码器,并创建一个 MP4 格式的输出文件。然后,我们使用 FFmpeg 解码输入文件并将解码后的帧编码为 H.264 格式,并将编码后的帧写入输出文件。最后,我们释放所有资源并退出程序。
请注意,这只是一个基础的示例代码,仅供参考。在实际应用中,你可能需要添加更多的错误处理和参数设置,以适应不同的情况。
阅读全文