libav api examples
/*
* rwav.c
*
* Author: Arash Shafiei
* Email: arash dot shafiei at gmail dot com
*/
#include "rwav.h"
#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
void rwav_register_all() {
av_register_all();
avcodec_register_all();
avdevice_register_all();
avformat_network_init();
}
int rwav_open_input_audio(InputAudioContext * p_in_audio_ctx) {
int i;
AVCodecContext * p_codec_ctx;
AVCodec * p_codec;
p_in_audio_ctx->p_fmt_ctx = NULL;
// Open video
if (avformat_open_input(&p_in_audio_ctx->p_fmt_ctx,
p_in_audio_ctx->psz_name, NULL, NULL) != 0) {
fprintf(stderr, "Cannot open file\n");
return -1;
}
// Retrieve stream information
if (avformat_find_stream_info(p_in_audio_ctx->p_fmt_ctx, NULL) < 0) {
fprintf(stderr, "Cannot find stream information\n");
return -1;
}
av_dump_format(p_in_audio_ctx->p_fmt_ctx, 0, p_in_audio_ctx->psz_name, 0);
// Find the first video stream
p_in_audio_ctx->i_audio_stream_idx = -1;
for (i = 0; i < p_in_audio_ctx->p_fmt_ctx->nb_streams; i++) {
if (p_in_audio_ctx->p_fmt_ctx->streams[i]->codec->codec_type
== AVMEDIA_TYPE_AUDIO) {
p_in_audio_ctx->i_audio_stream_idx = i;
}
}
if (p_in_audio_ctx->i_audio_stream_idx == -1) {
fprintf(stderr, "Cannot find a video stream\n");
return -1;
}
// Get a pointer to the p_codec context for the video stream
p_codec_ctx =
p_in_audio_ctx->p_fmt_ctx->streams[p_in_audio_ctx->i_audio_stream_idx]->codec;
// Find the decoder for the video stream
p_codec = avcodec_find_decoder(p_codec_ctx->codec_id);
if (p_codec == NULL) {
fprintf(stderr, "Input audio p_codec is not supported.\n");
avformat_close_input(&p_in_audio_ctx->p_fmt_ctx);
return -1;
}
// Open p_codec
if (avcodec_open2(p_codec_ctx, p_codec, NULL) < 0) {
fprintf(stderr, "Cannot open input audio p_codec.\n");
avformat_close_input(&p_in_audio_ctx->p_fmt_ctx);
return -1;
}
// Allocate video frame
p_in_audio_ctx->p_audio_frame = avcodec_alloc_frame();
return 0;
}
int rwav_open_input_video(InputVideoContext * p_in_video_ctx) {
int i;
AVCodecContext * p_codec_ctx;
AVCodec * p_codec;
p_in_video_ctx->p_fmt_ctx = NULL;
// Open video url
if (avformat_open_input(&p_in_video_ctx->p_fmt_ctx,
p_in_video_ctx->psz_name, NULL, NULL) != 0) {
fprintf(stderr, "Cannot open file\n");
return -1;
}
// Retrieve stream information
if (avformat_find_stream_info(p_in_video_ctx->p_fmt_ctx, NULL) < 0) {
fprintf(stderr, "Cannot find stream information\n");
return -1;
}
av_dump_format(p_in_video_ctx->p_fmt_ctx, 0, p_in_video_ctx->psz_name, 0);
// Find the first video stream
p_in_video_ctx->i_video_stream_idx = -1;
for (i = 0; i < p_in_video_ctx->p_fmt_ctx->nb_streams; i++) {
if (p_in_video_ctx->p_fmt_ctx->streams[i]->codec->codec_type
== AVMEDIA_TYPE_VIDEO) {
p_in_video_ctx->i_video_stream_idx = i;
}
}
if (p_in_video_ctx->i_video_stream_idx == -1) {
fprintf(stderr, "Cannot find a video stream\n");
return -1;
}
// Get a pointer to the codec context for the video stream
p_codec_ctx =
p_in_video_ctx->p_fmt_ctx->streams[p_in_video_ctx->i_video_stream_idx]->codec;
// Find the decoder for the video stream
p_codec = avcodec_find_decoder(p_codec_ctx->codec_id);
if (p_codec == NULL) {
fprintf(stderr, "Codec is not supported.\n");
avformat_close_input(&p_in_video_ctx->p_fmt_ctx);
return -1;
}
// Open codec
if (avcodec_open2(p_codec_ctx, p_codec, NULL) < 0) {
fprintf(stderr, "Cannot open codec.\n");
avformat_close_input(&p_in_video_ctx->p_fmt_ctx);
return -1;
}
// Allocate video frame
p_in_video_ctx->p_video_frame = avcodec_alloc_frame();
return 0;
}
int rwav_open_output_file(OutputFileContext * p_outfile_ctx) {
p_outfile_ctx->p_fmt_ctx = NULL;
AVOutputFormat * p_output_fmt;
//Find output format
p_output_fmt = av_guess_format(NULL, p_outfile_ctx->psz_name, NULL);
if (!p_output_fmt) {
fprintf(stderr, "Cannot find suitable output format\n");
return -1;
}
p_outfile_ctx->p_fmt_ctx = avformat_alloc_context();
if (!p_outfile_ctx->p_fmt_ctx) {
fprintf(stderr, "Cannot allocate memory for pOutVideoFormatCtx\n");
return -1;
}
p_outfile_ctx->p_fmt_ctx->oformat = p_output_fmt;
strcpy(p_outfile_ctx->p_fmt_ctx->filename, p_outfile_ctx->psz_name);
// Open the output file
if (!(p_output_fmt->flags & AVFMT_NOFILE)) {
if (avio_open(&p_outfile_ctx->p_fmt_ctx->pb, p_outfile_ctx->psz_name,
URL_WRONLY) < 0) {
fprintf(stderr, "Cannot not open '%s'\n", p_outfile_ctx->psz_name);
return -1;
}
}
return 0;
}
int rwav_open_output_video_stream(OutputFileContext * p_outfile_ctx,
OutputVideoContext * p_out_video_ctx) {
AVCodec * p_video_codec;
AVStream * p_video_stream;
int i_video_codec_id = CODEC_ID_H264;
p_video_codec = avcodec_find_encoder(i_video_codec_id);
if (p_video_codec == NULL) {
fprintf(stderr, "Output video codec not found\n");
return -1;
}
//Create new video stream
p_video_stream = avformat_new_stream(p_outfile_ctx->p_fmt_ctx,
p_video_codec);
if (!p_video_stream) {
fprintf(stderr, "Cannot create output video stream\n");
return -1;
}
p_video_stream->codec->codec_id = p_video_codec->id;
p_video_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
p_video_stream->codec->bit_rate = p_out_video_ctx->i_vbitrate;
p_video_stream->codec->width = p_out_video_ctx->i_vwidth;
p_video_stream->codec->height = p_out_video_ctx->i_vheight;
p_video_stream->codec->time_base =
(AVRational) {1 ,p_out_video_ctx->i_vframerate};
p_video_stream->codec->pix_fmt = PIX_FMT_YUV420P;
p_video_stream->codec->max_b_frames = 0;
p_video_stream->codec->thread_count = 1;
p_video_stream->codec->delay = 0;
p_video_stream->codec->gop_size = p_out_video_ctx->i_vframerate;
//videoStream->codec->gop_size = 1;
p_video_stream->codec->rc_lookahead = 0;
//videoStream->time_base = (AVRational) {1 , 1000000};
//videoStream->r_frame_rate = (AVRational) {outVideoCtx->video_framerate, 1};
//av_opt_set(videoStream->codec->priv_data, "preset", "slow", 0);
//videoStream->codec->me_range = 16;
//videoStream->codec->max_qdiff = 4;
//videoStream->codec->qmin = 10;
//videoStream->codec->qmax = 51;
//videoStream->codec->qcompress = 0.6;
//videoStream->codec->profile = FF_PROFILE_H264_BASELINE;
//videoStream->codec->level = 10;
if (p_outfile_ctx->p_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
p_video_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
p_outfile_ctx->i_video_stream_idx = p_video_stream->index;
// open the video codec
if (avcodec_open2(p_video_stream->codec, p_video_codec, NULL) < 0) {
fprintf(stderr, "Cannot open output video codec\n");
return -1;
}
//Initialize output frame
p_out_video_ctx->i_video_outbuf_size = 9 * p_out_video_ctx->i_vwidth
* p_out_video_ctx->i_vheight + 10000;
p_out_video_ctx->p_video_outbuf = (uint8_t *) av_malloc(
p_out_video_ctx->i_video_outbuf_size);
// Allocate an AVFrame structure
p_out_video_ctx->p_video_frame = avcodec_alloc_frame();
if (p_out_video_ctx->p_video_frame == NULL) {
fprintf(stderr, "Cannot allocate YUV frame!\n");
return -1;
}
// Determine required buffer size and allocate buffer
int i_num_bytes = avpicture_get_size(PIX_FMT_YUV420P,
p_out_video_ctx->i_vwidth, p_out_video_ctx->i_vheight);
p_out_video_ctx->p_video_data_buf = (uint8_t *) av_malloc(
i_num_bytes * sizeof(uint8_t));
avpicture_fill((AVPicture *) p_out_video_ctx->p_video_frame,
p_out_video_ctx->p_video_data_buf, PIX_FMT_YUV420P,
p_out_video_ctx->i_vwidth, p_out_video_ctx->i_vheight);
return 0;
}
int rwav_open_output_audio_stream(OutputFileContext * p_outfile_ctx,
OutputAudioContext * p_out_audio_ctx) {
AVCodec * p_audio_codec;
AVStream * p_audio_stream;
int i_audio_codec_id = CODEC_ID_AAC;
p_audio_codec = avcodec_find_encoder(i_audio_codec_id);
if (p_audio_codec == NULL) {
fprintf(stderr, "Output audio codec not found\n");
return -1;
}
//Create new audio stream
p_audio_stream = avformat_new_stream(p_outfile_ctx->p_fmt_ctx,
p_audio_codec);
if (!p_audio_stream) {
fprintf(stderr, "Cannot create output video stream\n");
return -1;
}
p_audio_stream->codec->codec_id = p_audio_codec->id;
p_audio_stream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
p_audio_stream->codec->bit_rate = p_out_audio_ctx->i_abitrate;
p_audio_stream->codec->sample_rate = p_out_audio_ctx->i_asamplerate;
p_audio_stream->codec->channels = p_out_audio_ctx->i_achannels;
p_audio_stream->codec->sample_fmt = AV_SAMPLE_FMT_S16;
if (p_outfile_ctx->p_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
p_audio_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
p_outfile_ctx->i_audio_stream_idx = p_audio_stream->index;
// open the audio codec
if (avcodec_open2(p_audio_stream->codec, p_audio_codec, NULL) < 0) {
fprintf(stderr, "Cannot open output audio codec\n");
return -1;
}
p_out_audio_ctx->p_audio_frame = avcodec_alloc_frame();
p_out_audio_ctx->p_fifo_buf = av_fifo_alloc(2 * MAX_AUDIO_PACKET_SIZE);
p_out_audio_ctx->p_audio_data_buf = (uint8_t*) av_malloc(
2 * MAX_AUDIO_PACKET_SIZE);
return 0;
}
int rwav_open_video_converter(InputVideoContext * p_in_video_ctx,
OutputVideoContext * p_out_video_ctx) {
AVCodecContext * p_codec_ctx;
// Get a pointer to the codec context for the video stream
p_codec_ctx =
p_in_video_ctx->p_fmt_ctx->streams[p_in_video_ctx->i_video_stream_idx]->codec;
p_out_video_ctx->p_sws_ctx = sws_getContext(p_codec_ctx->width,
p_codec_ctx->height, p_codec_ctx->pix_fmt,
p_out_video_ctx->i_vwidth, p_out_video_ctx->i_vheight,
PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);
if (p_out_video_ctx->p_sws_ctx == NULL) {
fprintf(stderr, "Cannot initialize the conversion context!\n");
return -1;
}
return 0;
}
int rwav_convert_video_frame(InputVideoContext * p_in_video_ctx,
OutputVideoContext * p_out_video_ctx) {
AVCodecContext * p_codec_ctx;
// Get a pointer to the codec context for the video stream
p_codec_ctx =
p_in_video_ctx->p_fmt_ctx->streams[p_in_video_ctx->i_video_stream_idx]->codec;
sws_scale(p_out_video_ctx->p_sws_ctx,
(const uint8_t * const *) p_in_video_ctx->p_video_frame->data,
p_in_video_ctx->p_video_frame->linesize, 0, p_codec_ctx->height,
p_out_video_ctx->p_video_frame->data,
p_out_video_ctx->p_video_frame->linesize);
p_out_video_ctx->p_video_frame->pts = p_in_video_ctx->p_video_frame->pts;
return 0;
}
int rwav_convert_audio_frame(InputAudioContext * p_in_audio_ctx,
OutputAudioContext * p_out_audio_ctx) {
p_out_audio_ctx->p_audio_inbuf = p_in_audio_ctx->p_audio_frame->data[0];
p_out_audio_ctx->i_audio_inbuf_size =
p_in_audio_ctx->p_audio_frame->linesize[0];
return 0;
}
int rwav_read_audio(InputAudioContext * p_in_audio_ctx) {
AVPacket pkt;
int i_got_frame;
AVCodecContext * p_codec_ctx;
// Get a pointer to the codec context for the video stream
p_codec_ctx =
p_in_audio_ctx->p_fmt_ctx->streams[p_in_audio_ctx->i_audio_stream_idx]->codec;
avcodec_get_frame_defaults(p_in_audio_ctx->p_audio_frame);
// Read frames
while (av_read_frame(p_in_audio_ctx->p_fmt_ctx, &pkt) >= 0) {
// Is this a packet from the audio stream?
if (pkt.stream_index == p_in_audio_ctx->i_audio_stream_idx) {
// Decode video frame
if (avcodec_decode_audio4(p_codec_ctx,
p_in_audio_ctx->p_audio_frame, &i_got_frame, &pkt) < 0) {
fprintf(stderr, "Error while decoding audio.\n");
return -1;
}
// Did we get a video frame?
if (i_got_frame) {
av_free_packet(&pkt);
return 0;
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&pkt);
}
return -1;
}
int rwav_read_video(InputVideoContext * p_in_video_ctx) {
AVPacket pkt;
int i_got_frame;
// Get a pointer to the codec context for the video stream
AVCodecContext * p_codec_ctx =
p_in_video_ctx->p_fmt_ctx->streams[p_in_video_ctx->i_video_stream_idx]->codec;
avcodec_get_frame_defaults(p_in_video_ctx->p_video_frame);
// Read frames
while (av_read_frame(p_in_video_ctx->p_fmt_ctx, &pkt) >= 0) {
// Is this a packet from the video stream?
if (pkt.stream_index == p_in_video_ctx->i_video_stream_idx) {
// Decode video frame
avcodec_decode_video2(p_codec_ctx, p_in_video_ctx->p_video_frame,
&i_got_frame, &pkt);
// Did we get a video frame?
if (i_got_frame) {
av_free_packet(&pkt);
return 0;
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&pkt);
}
return -1;
}
int rwav_write_video(OutputFileContext * p_outfile_ctx,
OutputVideoContext * p_out_video_ctx) {
AVPacket pkt;
int i_out_size = -1;
AVStream * p_video_stream =
p_outfile_ctx->p_fmt_ctx->streams[p_outfile_ctx->i_video_stream_idx];
AVCodecContext * p_video_codec_ctx = p_video_stream->codec;
//Set PTS
p_out_video_ctx->p_video_frame->pts = p_video_codec_ctx->frame_number;
//Set PTS (alternative method)
//int64_t now = av_gettime();
//outVideoCtx->pOutVideoFrame->pts = av_rescale_q(now,AV_TIME_BASE_Q,
// videoCodecCtx->time_base);
//Encoding video
i_out_size = avcodec_encode_video(p_video_codec_ctx,
p_out_video_ctx->p_video_outbuf,
p_out_video_ctx->i_video_outbuf_size,
p_out_video_ctx->p_video_frame);
//printf("After pts: %d\n", outVideoCtx->pOutVideoFrame->pts);
// if zero size, it means the image was buffered
if (i_out_size > 0) {
av_init_packet(&pkt);
if (p_video_codec_ctx->coded_frame->pts != AV_NOPTS_VALUE) {
pkt.pts = av_rescale_q(p_video_codec_ctx->coded_frame->pts,
p_video_codec_ctx->time_base, p_video_stream->time_base);
}
if (p_video_codec_ctx->coded_frame->key_frame)
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.stream_index = p_video_stream->index;
pkt.data = p_out_video_ctx->p_video_outbuf;
pkt.size = i_out_size;
// write the compressed frame in the media file
if (av_interleaved_write_frame(p_outfile_ctx->p_fmt_ctx, &pkt) != 0)
fprintf(stderr, "Writing frame is not successful\n");
av_free_packet(&pkt);
}
return i_out_size;
}
int rwav_write_audio(OutputFileContext * p_outfile_ctx,
OutputAudioContext * p_out_audio_ctx) {
AVPacket pkt;
int i_got_pkt;
int i_frame_bytes;
AVStream * p_audio_stream =
p_outfile_ctx->p_fmt_ctx->streams[p_outfile_ctx->i_audio_stream_idx];
AVCodecContext * p_audio_codec_ctx = p_audio_stream->codec;
int i_osize = av_get_bytes_per_sample(p_audio_codec_ctx->sample_fmt);
//Encoding audio
av_fifo_generic_write(p_out_audio_ctx->p_fifo_buf,
p_out_audio_ctx->p_audio_inbuf, p_out_audio_ctx->i_audio_inbuf_size,
NULL);
i_frame_bytes = p_audio_codec_ctx->frame_size * i_osize
* p_audio_codec_ctx->channels;
while (av_fifo_size(p_out_audio_ctx->p_fifo_buf) >= i_frame_bytes) {
av_fifo_generic_read(p_out_audio_ctx->p_fifo_buf,
p_out_audio_ctx->p_audio_data_buf, i_frame_bytes, NULL);
avcodec_get_frame_defaults(p_out_audio_ctx->p_audio_frame);
p_out_audio_ctx->p_audio_frame->nb_samples =
i_frame_bytes
/ (p_audio_codec_ctx->channels
* av_get_bytes_per_sample(
p_audio_codec_ctx->sample_fmt));
if (avcodec_fill_audio_frame(p_out_audio_ctx->p_audio_frame,
p_audio_codec_ctx->channels, p_audio_codec_ctx->sample_fmt,
p_out_audio_ctx->p_audio_data_buf, i_frame_bytes, 1) < 0) {
fprintf(stderr, "Fill audio frame failed\n");
return -1;
}
av_init_packet(&pkt);
//Set PTS
//int64_t now = av_gettime();
//outAudioCtx->pOutAudioFrame->pts = av_rescale_q(now,AV_TIME_BASE_Q,
// audioEncCtx->time_base);
if (avcodec_encode_audio2(p_audio_codec_ctx, &pkt,
p_out_audio_ctx->p_audio_frame, &i_got_pkt) != 0) {
fprintf(stderr, "Error while encoding audio.\n");
return -1;
}
if (i_got_pkt) {
pkt.stream_index = p_audio_stream->index;
/*
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, audioEncCtx->time_base,
audioStream->time_base);
*/
pkt.flags |= AV_PKT_FLAG_KEY;
if (av_interleaved_write_frame(p_outfile_ctx->p_fmt_ctx, &pkt)
!= 0) {
fprintf(stderr, "Writing frame is not successful\n");
av_free_packet(&pkt);
return -1;
}
av_free_packet(&pkt);
}
}
return 0;
}
int rwav_write_header(OutputFileContext * p_outfile_ctx) {
// write the stream header, if any
avformat_write_header(p_outfile_ctx->p_fmt_ctx, NULL);
return 0;
}
int rwav_write_tailer(OutputFileContext * p_outfile_ctx) {
// write the trailer, if any
av_write_trailer(p_outfile_ctx->p_fmt_ctx);
return 0;
}
int rwav_close_input_audio(InputAudioContext * p_in_audio_ctx) {
// Close the audio format context
avformat_close_input(&p_in_audio_ctx->p_fmt_ctx);
// Free the audio frame
av_free(p_in_audio_ctx->p_audio_frame);
return 0;
}
int rwav_close_input_video(InputVideoContext * p_in_video_ctx) {
// Close the video file
avformat_close_input(&p_in_video_ctx->p_fmt_ctx);
// Free the YUV frame
av_free(p_in_video_ctx->p_video_frame);
return 0;
}
int rwav_close_output_file(OutputFileContext * p_outfile_ctx) {
int i;
avio_close(p_outfile_ctx->p_fmt_ctx->pb);
// free the streams
for (i = 0; i < p_outfile_ctx->p_fmt_ctx->nb_streams; i++) {
avcodec_close(p_outfile_ctx->p_fmt_ctx->streams[i]->codec);
av_freep(&p_outfile_ctx->p_fmt_ctx->streams[i]->info);
}
// free the stream
avformat_free_context(p_outfile_ctx->p_fmt_ctx);
return 0;
}
int rwav_close_output_video_stream(OutputVideoContext * p_out_video_ctx) {
av_free(p_out_video_ctx->p_video_outbuf);
av_free(p_out_video_ctx->p_video_frame);
av_free(p_out_video_ctx->p_sws_ctx);
av_free(p_out_video_ctx->p_video_data_buf);
return 0;
}
int rwav_close_output_audio_stream(OutputAudioContext * p_out_audio_ctx) {
av_fifo_free(p_out_audio_ctx->p_fifo_buf);
av_free(p_out_audio_ctx->p_audio_data_buf);
av_free(p_out_audio_ctx->p_audio_frame);
return 0;
}