-
-
Save beandog/7f51cdd45cf7ca9c8e4fce33760dfc60 to your computer and use it in GitHub Desktop.
ffmpeg learning curve
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 <unistd.h> | |
#include <stdbool.h> | |
#include <libavcodec/avcodec.h> | |
#include <libavformat/avformat.h> | |
#include <libavformat/avio.h> | |
#include <libavutil/imgutils.h> | |
#include <libavutil/avstring.h> | |
#include <libavutil/audio_fifo.h> | |
#include <libswscale/swscale.h> | |
#include <libswresample/swresample.h> | |
#define OUTPUT_CHANNELS 2 | |
int main(int argc, char **argv) { | |
int retval = 0; | |
// Load all codecs | |
av_register_all(); | |
AVFormatContext *dvd_format_ctx = NULL; | |
AVDictionary *format_opts = NULL; | |
AVInputFormat *input_format = NULL; | |
if(argc == 2) | |
retval = avformat_open_input(&dvd_format_ctx, argv[1], input_format, &format_opts); | |
else | |
retval = avformat_open_input(&dvd_format_ctx, "video.mpg", input_format, &format_opts); | |
printf("* avformat_open_input: %i\n", retval); | |
retval = avformat_find_stream_info(dvd_format_ctx, NULL); | |
printf("* avformat_find_stream_info: %i\n", retval); | |
printf("* # streams: %u\n", dvd_format_ctx->nb_streams); | |
AVStream *video_stream = NULL; | |
AVStream *audio_stream = NULL; | |
unsigned int ix = 0; | |
for(ix = 0; ix < dvd_format_ctx->nb_streams; ix++) { | |
if(dvd_format_ctx->streams[ix]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { | |
printf("* stream %i is video\n", ix); | |
video_stream = dvd_format_ctx->streams[ix]; | |
} | |
if(dvd_format_ctx->streams[ix]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_stream == NULL) { | |
printf("* stream %i is audio\n", ix); | |
audio_stream = dvd_format_ctx->streams[ix]; | |
} | |
if(dvd_format_ctx->streams[ix]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) | |
printf("* stream %i is subtitle\n", ix); | |
/* | |
if(dvd_format_ctx->streams[ix]->codecpar->codec_type == AVMEDIA_TYPE_UNKNOWN) | |
printf("* stream %i is unknown\n", ix); | |
if(dvd_format_ctx->streams[ix]->codecpar->codec_type == AVMEDIA_TYPE_DATA) | |
printf("* stream %i is data\n", ix); | |
*/ | |
} | |
AVCodecParserContext *video_ctx = NULL; | |
video_ctx = video_stream->parser; | |
printf("* video start_time: %lu\n", video_stream->start_time); | |
printf("* video duration: %lu\n", video_stream->duration); | |
AVCodecParserContext *audio_ctx = NULL; | |
audio_ctx = audio_stream->parser; | |
printf("* audio start_time: %lu\n", audio_stream->start_time); | |
printf("* audio duration: %lu\n", audio_stream->duration); | |
AVCodec *video_codec = NULL; | |
AVCodec *audio_codec = NULL; | |
// video_codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO); | |
video_codec = avcodec_find_decoder(video_stream->codecpar->codec_id); | |
audio_codec = avcodec_find_decoder(audio_stream->codecpar->codec_id); | |
if(video_codec == NULL) | |
printf("* video codec: unknown\n"); | |
if(audio_codec == NULL) | |
printf("* audio codec: unknown\n"); | |
printf("* video codec name: %s\n", video_codec->name); | |
printf("* audio codec name: %s\n", audio_codec->name); | |
AVCodecContext *video_codec_context = NULL; | |
AVCodecContext *audio_codec_context = NULL; | |
video_codec_context = avcodec_alloc_context3(video_codec); | |
audio_codec_context = avcodec_alloc_context3(audio_codec); | |
if(video_codec_context == NULL) | |
printf("* Couldn't alloc video context\n"); | |
if(audio_codec_context == NULL) | |
printf("* Couldn't alloc audio context\n"); | |
// Take data from the stream and put it into the new context | |
avcodec_parameters_to_context(video_codec_context, video_stream->codecpar); | |
avcodec_parameters_to_context(audio_codec_context, audio_stream->codecpar); | |
retval = avcodec_open2(video_codec_context, video_codec, NULL); | |
retval = avcodec_open2(audio_codec_context, audio_codec, NULL); | |
printf("* audio channels: %i\n", audio_codec_context->channels); | |
printf("* audio bitrate: %lu\n", audio_codec_context->bit_rate); | |
AVFrame *video_frame = NULL; | |
AVFrame *audio_frame = NULL; | |
video_frame = av_frame_alloc(); | |
audio_frame = av_frame_alloc(); | |
// Set up new AAC codec | |
AVCodec *aac_codec = NULL; | |
aac_codec = avcodec_find_encoder(AV_CODEC_ID_AAC); | |
// Set up new AAC context | |
AVCodecContext *aac_codec_context = NULL; | |
aac_codec_context = avcodec_alloc_context3(aac_codec); | |
aac_codec_context->channels = OUTPUT_CHANNELS; | |
aac_codec_context->channel_layout = (uint64_t)av_get_default_channel_layout(OUTPUT_CHANNELS); | |
aac_codec_context->sample_rate = audio_codec_context->sample_rate; | |
aac_codec_context->sample_fmt = aac_codec->sample_fmts[0]; | |
aac_codec_context->bit_rate = audio_codec_context->bit_rate; | |
aac_codec_context->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; | |
aac_codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; | |
// printf("* sample_fmt name: %s\n", av_get_sample_fmt_name(aac_codec->sample_fmts[0])); | |
// Create new output format | |
AVFormatContext *output_format = NULL; | |
AVIOContext *output_io_context = NULL; | |
const char m4a_filename[] = "audio.aac"; | |
output_format = avformat_alloc_context(); | |
avio_open(&output_io_context, m4a_filename, AVIO_FLAG_WRITE); | |
output_format->pb = output_io_context; | |
output_format->oformat = av_guess_format(NULL, m4a_filename, NULL); | |
av_strlcpy(output_format->filename, m4a_filename, sizeof(output_format->filename)); | |
// Set up new audio stream | |
AVStream *m4a_stream = NULL; | |
m4a_stream = avformat_new_stream(output_format, aac_codec); | |
m4a_stream->time_base.den = aac_codec_context->sample_rate; // setting manually, see above | |
m4a_stream->time_base.num = 1; | |
// Create new codec | |
avcodec_open2(aac_codec_context, aac_codec, NULL); | |
retval = avcodec_parameters_from_context(m4a_stream->codecpar, aac_codec_context); | |
// Context to convert audio | |
SwrContext *audio_convert_context = NULL; | |
audio_convert_context = swr_alloc_set_opts(NULL, av_get_default_channel_layout(aac_codec_context->channels), aac_codec_context->sample_fmt, aac_codec_context->sample_rate, av_get_default_channel_layout(audio_codec_context->channels), audio_codec_context->sample_fmt, audio_codec_context->sample_rate, 0, NULL); | |
swr_init(audio_convert_context); | |
// New FIFO to handle incoming/outcoming data | |
AVAudioFifo *audio_fifo = NULL; | |
audio_fifo = av_audio_fifo_alloc(aac_codec_context->sample_fmt, aac_codec_context->channels, 1); | |
// Begin writing to audio.aac (only creates an empty file for now) | |
retval = avformat_write_header(output_format, NULL); | |
av_dump_format(output_format, 0, m4a_filename, 1); | |
// Description of the decompressed (raw) data | |
AVFrame *aac_frame = NULL; | |
aac_frame = av_frame_alloc(); | |
AVFrame *dvd_frame = NULL; | |
dvd_frame = av_frame_alloc(); | |
// Storage of the compressed data | |
AVPacket dvd_packet; | |
av_init_packet(&dvd_packet); | |
// Pull one frame into the audio packet | |
retval = av_read_frame(dvd_format_ctx, &dvd_packet); | |
printf("* retval: %i\n", retval); | |
/* | |
while((retval = av_read_frame(dvd_format_ctx, &dvd_packet)) != AVERROR_EOF) | |
printf("* pass one: reading frame, stream index: %i, retval: %i\r", dvd_packet.stream_index, retval); | |
printf("* read all frames\n"); | |
*/ | |
int num_fail = 0, num_pass = 0; | |
static char error_buffer[255]; | |
while((retval = av_read_frame(dvd_format_ctx, &dvd_packet)) != AVERROR_EOF) { | |
if(dvd_packet.stream_index != 2) { | |
av_packet_unref(&dvd_packet); | |
continue; | |
} | |
retval = avcodec_send_packet(audio_codec_context, &dvd_packet); | |
printf("* send packet retval: %i\n", retval); | |
retval = avcodec_receive_frame(audio_codec_context, dvd_frame); | |
printf("* receive frame retval: %i\n", retval); | |
av_packet_unref(&dvd_packet); | |
} | |
printf("* num pass: %i num fail: %i\n", num_pass, num_fail); | |
// Prepare to send to audio decoder | |
// retval = avcodec_send_packet(audio_codec_context, &dvd_packet); | |
// printf("* retval: %i\n", retval); | |
/* | |
ix = 0; | |
int got_frame = 0; | |
int num_pass = 0; | |
int num_fail = 0; | |
while((retval = av_read_frame(dvd_format_ctx, &dvd_packet)) == 0) { | |
ix++; | |
retval = avcodec_send_packet(audio_codec_context, &dvd_packet); | |
// retval = avcodec_decode_audio4(audio_codec_context, input_frame, &got_frame, &dvd_packet); | |
if(retval < 0) { | |
// printf("* frame: %i FAIL--\n", ix); | |
// av_strerror(retval, error_buffer, sizeof(error_buffer)); | |
// printf("error: %s\n", error_buffer); | |
// printf("exiting\n"); | |
// return 1; | |
num_fail++; | |
} else { | |
// printf("* frame: %010i pts: %lu dts: %lu size: %i index: %i duration: %lu pos: %lo\n", ix, dvd_packet.pts, dvd_packet.dts, dvd_packet.size, dvd_packet.stream_index, dvd_packet.duration, dvd_packet.pos); | |
// printf("* frame: %i PASS++\n", ix); | |
num_pass++; | |
// retval = avcodec_receive_frame( | |
retval = avcodec_send_packet(aac_codec_context, &dvd_packet); | |
printf("* retval: %i\n", retval); | |
} | |
} | |
printf("* PASS: %i FAIL: %i\n", num_pass, num_fail); | |
*/ | |
// retval = avcodec_decode_audio4(audio_codec_context, input_frame, &got_frame, &dvd_packet); | |
// retval = avcodec_send_packet(audio_codec_context, &dvd_packet); | |
// av_strerror(retval, error_buffer, sizeof(error_buffer)); | |
// printf("error: %s\n", error_buffer); | |
swr_free(&audio_convert_context); | |
avcodec_free_context(&video_codec_context); | |
avcodec_free_context(&audio_codec_context); | |
av_frame_free(&video_frame); | |
av_frame_free(&audio_frame); | |
avformat_close_input(&dvd_format_ctx); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment