[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