Created
October 24, 2023 11:39
-
-
Save J0sueTM/78308eefaa130153e4a513767a0b9dcc to your computer and use it in GitHub Desktop.
ffmpeg encode video
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <libavcodec/avcodec.h> | |
#include <libavutil/opt.h> | |
#include <libavutil/imgutils.h> | |
#include <libavutil/error.h> | |
static void print_ret_error(int ret) { | |
char buf[AV_ERROR_MAX_STRING_SIZE]; | |
av_strerror(ret, buf, sizeof(buf)); | |
printf("%s\n", buf); | |
} | |
static void encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *packet, FILE *output) { | |
int ret = avcodec_send_frame(ctx, frame); | |
if (ret < 0) { | |
printf("failed to send frame %ld to encoder\n", frame->pts); | |
print_ret_error(ret); | |
exit(1); | |
} | |
while (ret >= 0) { | |
ret = avcodec_receive_packet(ctx, packet); | |
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { | |
return; | |
} else if (ret < 0) { | |
printf("failed to encode frame %ld\n", frame->pts); | |
print_ret_error(ret); | |
exit(1); | |
} | |
printf("writing packet %ld (size=%5d)\n", packet->pts, packet->size); | |
fwrite(packet->data, 1, packet->size, output); | |
av_packet_unref(packet); | |
} | |
} | |
int main(int _argc, char **_argv) { | |
if (_argc <= 2) { | |
printf("usage: %s <codec name> <output file>\n", _argv[0]); | |
return 0; | |
} | |
const char *codec_name = _argv[1]; | |
const char *filename = _argv[2]; | |
const AVCodec *codec = avcodec_find_encoder_by_name(codec_name); | |
if (!codec) { | |
printf("failed to find encoder codec\n"); | |
return 1; | |
} | |
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec); | |
if (!codec_ctx) { | |
printf("failed to alloc codec context\n"); | |
return 1; | |
} | |
codec_ctx->bit_rate = 400000; | |
codec_ctx->width = 352; | |
codec_ctx->height = 288; | |
codec_ctx->time_base = (AVRational){1, 25}; | |
codec_ctx->framerate = (AVRational){25, 1}; | |
codec_ctx->gop_size = 10; | |
codec_ctx->max_b_frames = 1; | |
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; | |
if (codec->id == AV_CODEC_ID_H264) { | |
av_opt_set(codec_ctx->priv_data, "preset", "slow", 0); | |
} | |
int ret = avcodec_open2(codec_ctx, codec, NULL); | |
if (ret < 0) { | |
printf("failed to open codec\n"); | |
return 1; | |
} | |
FILE *output = fopen(filename, "wb"); | |
if (!output) { | |
printf("failed to open output file\n"); | |
return 1; | |
} | |
AVFrame *frame = av_frame_alloc(); | |
AVPacket *packet = av_packet_alloc(); | |
if (!packet || !frame) { | |
printf("failed to alloc packet or frame\n"); | |
return 1; | |
} | |
frame->format = codec_ctx->pix_fmt; | |
frame->width = codec_ctx->width; | |
frame->height = codec_ctx->height; | |
ret = av_frame_get_buffer(frame, 0); | |
if (ret < 0) { | |
printf("failed to allocate video frame data\n"); | |
} | |
for (int i = 0; i < (10 * 25); ++i) { | |
ret = av_frame_make_writable(frame); | |
if (ret < 0) { | |
printf("failed to make frame writable\n"); | |
return 1; | |
} | |
// luma (Y) | |
for (int y = 0; y < codec_ctx->height; ++y) { | |
for (int x = 0; x < codec_ctx->width; ++x) { | |
frame->data[0][y * frame->linesize[0] + x] = x + y + i * 4; | |
} | |
} | |
for (int y = 0; y < codec_ctx->height * 0.5f; ++y) { | |
for (int x = 0; x < codec_ctx->width * 0.5f; ++x) { | |
// chroma blue (U) | |
frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 5; | |
// chroma red (V) | |
frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 2; | |
} | |
} | |
frame->pts = i; | |
encode(codec_ctx, frame, packet, output); | |
} | |
encode(codec_ctx, NULL, packet, output); | |
fclose(output); | |
avcodec_free_context(&codec_ctx); | |
av_frame_free(&frame); | |
av_packet_free(&packet); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment