Skip to content

Instantly share code, notes, and snippets.

@beandog

beandog/avbox.c Secret

Created May 11, 2017 05:53
Show Gist options
  • Save beandog/7f51cdd45cf7ca9c8e4fce33760dfc60 to your computer and use it in GitHub Desktop.
Save beandog/7f51cdd45cf7ca9c8e4fce33760dfc60 to your computer and use it in GitHub Desktop.
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