ffmpeg learning curve
| #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