[Libav-user] Example for recompressing a video?
jettoblack
jettoblack at gmail.com
Wed Jun 6 02:48:29 CEST 2012
Hi Nicolas,
Very helpful, thank you.
I trimmed this code down to just the essentials of the audio section since
video isn't a problem.
What I see is that:
- The call to avresample_convert() seems to always succeed, so I think
decode and resample are working ok
- The first call to avcodec_encode_audio2() succeeds and returns a packet
(got_packet_ptr true), which is successfully written to the output
- Subsequent calls to avcodec_encode_audio2() return -22 (Illegal argument)
and got_packet_ptr false
Here is some sample output from the code below:
begin input loop
src pkt stream 1, pts 125098, dts 125098
got_audio linesize[0]=2304 nb_samples=1152
avr_convert() ret len 1152
destaudio pts 125098
avcodec_encode_audio2() success
write audio pkt: stream 0, pts 124617, dts 124617
src pkt stream 1, pts 127258, dts 127258
got_audio linesize[0]=2304 nb_samples=1152
avr_convert() ret len 1152
destaudio pts 127258
avcodec_encode_audio2() error -22 Invalid argument
Any ideas? Thanks again!
Code:
#include <stdio.h>
#include <assert.h>
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavresample/avresample.h"
#include "libavutil/opt.h"
int main (int argc, const char * argv[])
{
const char *infile = argv[1];
const char *outfile = argv[2];
int r;
AVPacket pkt;
AVFrame *srcaudio = NULL;
AVFormatContext *in = NULL, *out = NULL;
AVCodecContext *in_acodec, *out_acodec;
AVStream *in_astream, *out_astream;
AVAudioResampleContext *avr;
AVCodec *acodec;
int got_audio;
char errbuf[128];
int got_packet_ptr = 0;
int audio_bufsize = AVCODEC_MAX_AUDIO_FRAME_SIZE +
FF_INPUT_BUFFER_PADDING_SIZE;
int64_t audio_samples = 0;
int64_t first_pts = -1;
// init LAVF
av_register_all();
avformat_network_init();
//av_log_set_level(AV_LOG_VERBOSE);
// Open input file
printf("Open input file: %s\n", infile);
r = avformat_open_input(&in, infile, NULL, NULL);
if (r) {
printf("open err %x\n", r);
return r;
}
r = avformat_find_stream_info(in, NULL);
if (r < 0) {
printf("find_stream_info err %x\n", r);
return r;
}
// iterate over input streams
for (int i = 0; i < in->nb_streams; i++) {
AVStream *inputStream = in->streams[i];
if (inputStream->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
inputStream->discard = AVDISCARD_NONE;
in_astream = inputStream;
in_acodec = inputStream->codec;
if (!inputStream->codec->codec) {
avcodec_open2(inputStream->codec,
avcodec_find_decoder(inputStream->codec->codec_id), NULL);
}
printf("Input audio %s rate %d channels %d sample_format %d\n",
in_acodec->codec->name,
in_acodec->sample_rate, in_acodec->channels,
in_acodec->sample_fmt);
}
else {
inputStream->discard = AVDISCARD_ALL;
}
}
assert(in_acodec);
// Open output file for writing
out = avformat_alloc_context();
assert(out);
out->oformat = av_guess_format(NULL, outfile, NULL); // Guess output
container format based on file extension
assert(out->oformat);
// Output parameters
// Audio codec
acodec = avcodec_find_encoder(CODEC_ID_MP2);
assert(acodec);
out_acodec = avcodec_alloc_context3(acodec);
avcodec_get_context_defaults3(out_acodec, acodec);
assert(out_acodec);
out_acodec->channels = 2;
out_acodec->sample_rate = 48000;
out_acodec->sample_fmt = AV_SAMPLE_FMT_S16;
out_acodec->channel_layout = av_get_channel_layout("stereo");
out_acodec->time_base = in_acodec->time_base;
// TODO: set other codec parameters
r = avcodec_open2(out_acodec, acodec, NULL);
assert(!r);
// Audio stream
out_astream = avformat_new_stream(out, out_acodec->codec);
assert(out_astream);
out_astream->codec = out_acodec;
// setup audio resample context
avr = avresample_alloc_context();
av_opt_set_int(avr, "in_channel_layout", in_acodec ->channel_layout,
0);
av_opt_set_int(avr, "out_channel_layout", out_acodec->channel_layout,
0);
av_opt_set_int(avr, "in_sample_fmt", in_acodec ->sample_fmt,
0);
av_opt_set_int(avr, "out_sample_fmt", out_acodec->sample_fmt,
0);
av_opt_set_int(avr, "in_sample_rate", in_acodec ->sample_rate,
0);
av_opt_set_int(avr, "out_sample_rate", out_acodec->sample_rate,
0);
av_opt_set_int(avr, "in_channels", in_acodec ->channels, 0);
av_opt_set_int(avr, "out_channels", out_acodec->channels, 0);
r = avresample_open(avr);
assert(!r);
// print audio params
printf("Output audio %s rate %d channels %d sample_format %d\n",
out_acodec->codec->name, out_acodec->sample_rate, out_acodec->channels,
out_acodec->sample_fmt);
// Begin writing output file
printf("Open output file: %s\nOutput container: %s\n", outfile,
out->oformat->long_name);
r = avio_open2(&out->pb, outfile, AVIO_FLAG_WRITE, NULL, NULL);
if (r) {
printf("err %x\n", r);
return r;
}
printf("write out header\n");
r = avformat_write_header(out, NULL);
if (r) {
printf("err %x\n", r);
return r;
}
printf("begin input loop\n");
while (1) {
av_init_packet(&pkt);
r = av_read_frame(in, &pkt);
if (r) {
if (r == AVERROR_EOF)
printf("EOF\n");
else
printf("read error %x\n", r);
break;
}
printf("src pkt stream %d, pts %"PRId64", dts %"PRId64"\n",
pkt.stream_index, pkt.pts, pkt.dts);
if (first_pts == -1 && pkt.pts != AV_NOPTS_VALUE)
first_pts = pkt.pts;
if (pkt.stream_index == in_astream->index) {
// decode audio
srcaudio = avcodec_alloc_frame();
avcodec_get_frame_defaults(srcaudio);
got_audio = 0;
r = avcodec_decode_audio4(in_acodec, srcaudio, &got_audio,
&pkt);
if (r < 0) {
av_strerror(r, errbuf, 128);
printf("audio decode error %d %s\n", r, errbuf);
break;
}
else if (got_audio) {
// convert audio
AVPacket newpkt;
AVFrame *destaudio; // frame for resampled audio
int64_t timestamp =
av_frame_get_best_effort_timestamp(srcaudio);
int nb_samples;
av_init_packet(&newpkt);
destaudio = avcodec_alloc_frame();
avcodec_get_frame_defaults(destaudio);
destaudio->extended_data = av_malloc(sizeof(uint8_t*));
destaudio->extended_data[0] = av_malloc(audio_bufsize);
got_packet_ptr = 0;
printf("got_audio linesize[0]=%d nb_samples=%d\n",
srcaudio->linesize[0], srcaudio->nb_samples);
// resample to dest format
nb_samples = avresample_convert(avr,
(void**)destaudio->extended_data,
destaudio->linesize[0], audio_bufsize,
(void**)srcaudio->extended_data,
srcaudio->linesize[0], srcaudio->nb_samples);
if (nb_samples < 0) {
av_strerror(nb_samples, errbuf, 128);
printf("avr_convert() error %d %s\n", nb_samples,
errbuf);
break;
}
printf("avr_convert() ret len %d\n", nb_samples);
if (timestamp != AV_NOPTS_VALUE)
destaudio->pts = av_rescale_q(timestamp,
in_astream->time_base, out_astream->time_base);
else
destaudio->pts = first_pts + (int)((double)audio_samples
* (90000.0/out_acodec->sample_rate));
printf("destaudio pts %"PRId64"\n", destaudio->pts);
// why does this return -22 after the first successfull
call?
r = avcodec_encode_audio2(out_acodec, &newpkt, destaudio,
&got_packet_ptr);
if (r < 0) {
av_strerror(r, errbuf, 128);
printf("avcodec_encode_audio2() error %d %s\n", r,
errbuf);
//break;
}
else if (got_packet_ptr) {
// write frame
printf("avcodec_encode_audio2() success\n");
newpkt.stream_index = out_astream->index;
newpkt.flags |= AV_PKT_FLAG_KEY;
printf("write audio pkt: stream %d, pts %"PRId64", dts
%"PRId64"\n",
newpkt.stream_index, newpkt.pts, newpkt.dts);
r = av_interleaved_write_frame(out, &newpkt);
if (r) {
printf("audio write error %x\n", r);
break;
}
}
av_free(destaudio->extended_data[0]);
av_free(destaudio->extended_data);
av_free(destaudio);
av_free_packet(&newpkt);
audio_samples += nb_samples;
}
av_free(srcaudio);
}
av_free_packet(&pkt);
}
avcodec_close(in_acodec);
avcodec_close(out_acodec);
// TODO: anything else to free/close?
r = av_write_trailer(out);
if (r) {
printf("error closing output %x\n", r);
}
avformat_close_input(&in);
printf("Wrote output file: %s\n", outfile);
return 0;
}
--
View this message in context: http://libav-users.943685.n4.nabble.com/Example-for-recompressing-a-video-tp4655098p4655143.html
Sent from the libav-users mailing list archive at Nabble.com.
More information about the Libav-user
mailing list