ffmepg c语言 dav转mp4 vs代码
时间: 2024-06-09 12:10:58 浏览: 121
你可以使用FFmpeg库来将DAV视频文件转换为MP4格式。以下是一个简单的C语言程序,使用FFmpeg实现此功能:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
int main(int argc, char *argv[]) {
AVFormatContext *input_ctx = NULL, *output_ctx = NULL;
AVCodecContext *decoder_ctx = NULL, *encoder_ctx = NULL;
AVCodec *decoder = NULL, *encoder = NULL;
AVFrame *frame = NULL, *tmp_frame = NULL;
AVPacket *pkt = NULL;
int ret = 0, video_stream_index = -1, len = 0;
char *input_file = NULL, *output_file = NULL;
if (argc != 3) {
fprintf(stderr, "Usage: %s <input_file> <output_file>\n", argv[0]);
exit(1);
}
input_file = argv[1];
output_file = argv[2];
// open input file
if ((ret = avformat_open_input(&input_ctx, input_file, NULL, NULL)) < 0) {
fprintf(stderr, "Failed to open input file: %s\n", av_err2str(ret));
goto end;
}
// retrieve stream information
if ((ret = avformat_find_stream_info(input_ctx, NULL)) < 0) {
fprintf(stderr, "Failed to retrieve input stream information: %s\n", av_err2str(ret));
goto end;
}
// find video stream
for (int i = 0; i < input_ctx->nb_streams; i++) {
if (input_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_index = i;
break;
}
}
if (video_stream_index == -1) {
fprintf(stderr, "Failed to find video stream\n");
goto end;
}
// allocate decoder context
decoder = avcodec_find_decoder(input_ctx->streams[video_stream_index]->codecpar->codec_id);
if (!decoder) {
fprintf(stderr, "Failed to find decoder\n");
goto end;
}
decoder_ctx = avcodec_alloc_context3(decoder);
if (!decoder_ctx) {
fprintf(stderr, "Failed to allocate decoder context\n");
goto end;
}
// copy codec parameters to decoder context
if ((ret = avcodec_parameters_to_context(decoder_ctx, input_ctx->streams[video_stream_index]->codecpar)) < 0) {
fprintf(stderr, "Failed to copy codec parameters to decoder context: %s\n", av_err2str(ret));
goto end;
}
// open decoder
if ((ret = avcodec_open2(decoder_ctx, decoder, NULL)) < 0) {
fprintf(stderr, "Failed to open decoder: %s\n", av_err2str(ret));
goto end;
}
// allocate encoder context
encoder = avcodec_find_encoder(AV_CODEC_ID_MPEG4);
if (!encoder) {
fprintf(stderr, "Failed to find encoder\n");
goto end;
}
encoder_ctx = avcodec_alloc_context3(encoder);
if (!encoder_ctx) {
fprintf(stderr, "Failed to allocate encoder context\n");
goto end;
}
// set encoder parameters
encoder_ctx->bit_rate = 400000;
encoder_ctx->width = decoder_ctx->width;
encoder_ctx->height = decoder_ctx->height;
encoder_ctx->time_base = decoder_ctx->time_base;
encoder_ctx->framerate = decoder_ctx->framerate;
encoder_ctx->gop_size = 10;
encoder_ctx->max_b_frames = 1;
encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
// open encoder
if ((ret = avcodec_open2(encoder_ctx, encoder, NULL)) < 0) {
fprintf(stderr, "Failed to open encoder: %s\n", av_err2str(ret));
goto end;
}
// allocate frame
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Failed to allocate frame\n");
goto end;
}
// allocate temporary frame
tmp_frame = av_frame_alloc();
if (!tmp_frame) {
fprintf(stderr, "Failed to allocate temporary frame\n");
goto end;
}
// allocate packet
pkt = av_packet_alloc();
if (!pkt) {
fprintf(stderr, "Failed to allocate packet\n");
goto end;
}
// open output file
if ((ret = avformat_alloc_output_context2(&output_ctx, NULL, NULL, output_file)) < 0) {
fprintf(stderr, "Failed to allocate output context: %s\n", av_err2str(ret));
goto end;
}
// add video stream to output context
AVStream *out_stream = avformat_new_stream(output_ctx, NULL);
if (!out_stream) {
fprintf(stderr, "Failed to allocate output stream\n");
goto end;
}
// copy codec parameters from encoder context to output stream
if ((ret = avcodec_parameters_from_context(out_stream->codecpar, encoder_ctx)) < 0) {
fprintf(stderr, "Failed to copy codec parameters from encoder context to output stream: %s\n", av_err2str(ret));
goto end;
}
// set time base for output stream
out_stream->time_base = encoder_ctx->time_base;
// write header to output file
if ((ret = avformat_write_header(output_ctx, NULL)) < 0) {
fprintf(stderr, "Failed to write header to output file: %s\n", av_err2str(ret));
goto end;
}
// read packets from input file, decode them, and encode them to output file
while (av_read_frame(input_ctx, pkt) >= 0) {
if (pkt->stream_index != video_stream_index) {
av_packet_unref(pkt);
continue;
}
// decode packet
len = avcodec_send_packet(decoder_ctx, pkt);
if (len < 0) {
fprintf(stderr, "Failed to decode packet: %s\n", av_err2str(len));
goto end;
}
while (len >= 0) {
// get decoded frame
len = avcodec_receive_frame(decoder_ctx, tmp_frame);
if (len == AVERROR(EAGAIN) || len == AVERROR_EOF) {
break;
} else if (len < 0) {
fprintf(stderr, "Failed to receive decoded frame: %s\n", av_err2str(len));
goto end;
}
// convert frame to output format
if (tmp_frame->format != encoder_ctx->pix_fmt || tmp_frame->width != encoder_ctx->width || tmp_frame->height != encoder_ctx->height) {
if (frame) {
av_frame_free(&frame);
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Failed to allocate frame\n");
goto end;
}
frame->format = encoder_ctx->pix_fmt;
frame->width = encoder_ctx->width;
frame->height = encoder_ctx->height;
if ((ret = av_frame_get_buffer(frame, 32)) < 0) {
fprintf(stderr, "Failed to allocate frame buffer: %s\n", av_err2str(ret));
goto end;
}
// convert frame
struct SwsContext *sws_ctx = sws_getContext(tmp_frame->width, tmp_frame->height, (enum AVPixelFormat)tmp_frame->format,
encoder_ctx->width, encoder_ctx->height, encoder_ctx->pix_fmt,
SWS_BILINEAR, NULL, NULL, NULL);
if (!sws_ctx) {
fprintf(stderr, "Failed to allocate SwsContext\n");
goto end;
}
sws_scale(sws_ctx, tmp_frame->data, tmp_frame->linesize, 0, tmp_frame->height, frame->data, frame->linesize);
sws_freeContext(sws_ctx);
} else {
frame = tmp_frame;
tmp_frame = NULL;
}
// encode frame
len = avcodec_send_frame(encoder_ctx, frame);
if (len < 0) {
fprintf(stderr, "Failed to encode frame: %s\n", av_err2str(len));
goto end;
}
while (len >= 0) {
// get encoded packet
len = avcodec_receive_packet(encoder_ctx, pkt);
if (len == AVERROR(EAGAIN) || len == AVERROR_EOF) {
break;
} else if (len < 0) {
fprintf(stderr, "Failed to receive encoded packet: %s\n", av_err2str(len));
goto end;
}
// write packet to output file
if ((ret = av_write_frame(output_ctx, pkt)) < 0) {
fprintf(stderr, "Failed to write packet to output file: %s\n", av_err2str(ret));
goto end;
}
av_packet_unref(pkt);
}
}
av_packet_unref(pkt);
}
// flush encoder
if ((ret = avcodec_send_frame(encoder_ctx, NULL)) < 0) {
fprintf(stderr, "Failed to flush encoder: %s\n", av_err2str(ret));
goto end;
}
while (ret >= 0) {
ret = avcodec_receive_packet(encoder_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
fprintf(stderr, "Failed to receive encoded packet: %s\n", av_err2str(ret));
goto end;
}
// write packet to output file
if ((ret = av_write_frame(output_ctx, pkt)) < 0) {
fprintf(stderr, "Failed to write packet to output file: %s\n", av_err2str(ret));
goto end;
}
av_packet_unref(pkt);
}
// write trailer to output file
if ((ret = av_write_trailer(output_ctx)) < 0) {
fprintf(stderr, "Failed to write trailer to output file: %s\n", av_err2str(ret));
goto end;
}
printf("Finished converting %s to %s\n", input_file, output_file);
end:
if (input_ctx) {
avformat_close_input(&input_ctx);
}
if (output_ctx) {
avio_closep(&output_ctx->pb);
avformat_free_context(output_ctx);
}
if (decoder_ctx) {
avcodec_free_context(&decoder_ctx);
}
if (encoder_ctx) {
avcodec_free_context(&encoder_ctx);
}
if (frame) {
av_frame_free(&frame);
}
if (tmp_frame) {
av_frame_free(&tmp_frame);
}
if (pkt) {
av_packet_free(&pkt);
}
return ret < 0;
}
```
此程序使用了FFmpeg的AVFormatContext、AVCodecContext、AVCodec、AVFrame、AVPacket和SwsContext等结构体/函数。使用VS Code编写C代码时,需要配置好FFmpeg的库文件和头文件路径。可以在VS Code的tasks.json文件中添加以下代码:
```json
{
"label": "build",
"type": "shell",
"command": "gcc",
"args": [
"-g",
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe",
"${file}",
"-lavcodec",
"-lavformat",
"-lavutil",
"-lswscale",
"-lmingw32",
"-lSDL2main",
"-lSDL2",
"-I${workspaceFolder}\\include",
"-L${workspaceFolder}\\lib",
"-Wl,-Bstatic",
"-lstdc++",
"-lpng",
"-lz",
"-lm",
"-Wl,-Bdynamic",
"-lwinmm",
"-lole32",
"-loleaut32",
"-luuid",
"-lcomctl32",
"-lcomdlg32"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\\\d+):(\\\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
}
```
此处假设你的FFmpeg库文件和头文件保存在VS Code工作区的lib和include文件夹中。你需要根据实际情况修改这些路径。然后,你可以使用Ctrl+Shift+B命令来编译和运行程序。
阅读全文