>
> Does libav have a setting to support encoding H.264 video and AAC audio
> into
> a MPEG2 TS stream? Any hints would be helpful.
>

Yes, this can get you started.

-- Jose

  #include <string.h>
#define __STDC_CONSTANT_MACROS

#include <iostream>
#include <queue>
#include <pthread.h>
#include <sys/time.h>

extern "C" {
    #include "libavcodec/avcodec.h"
    #include "libavcodec/opt.h"
    #include "libavformat/avformat.h"
    #include "libswscale/swscale.h"
}


#define DEBUG std::cout
#define endlog std::endl
#define FLUSH std::cout.flush();

char* filename = 0;
int g_width = 0;
int g_height = 0;

int IO_read_packet(void *me, uint8_t *buffer, int buf_size)
{
    static FILE* file = 0;
    if (!file) file = fopen(filename, "rb");
    if (!file) abort();

    int len = fread(buffer, 1, buf_size, file);
    //DEBUG << "read " << buf_size << " Got " << len << endlog;
    return len;
}

int IO_write_packet(void *opaque, uint8_t *buffer, int buf_size)
{
    static FILE* file = 0;
    if (!file) file = fopen("output.ts", "wb");
    if (!file) abort();

    int len = fwrite(buffer, 1, buf_size, file);
    //DEBUG << "written " << buf_size << " ts " << buf_size/188.0 << endlog;
    return len;
}


void setupVideoEncode(AVCodecContext* c)
{
    c->codec_type = CODEC_TYPE_VIDEO;
    c->codec_id = CODEC_ID_H264;
    c->bit_rate = 1000000;
    c->bit_rate_tolerance = 40000;
    c->width = g_width;
    c->height = g_height;
    c->time_base.num = 1;
    c->time_base.den = 60;
    c->gop_size = 5;
    c->keyint_min = 5;
    c->sample_aspect_ratio = av_d2q(1, 255);

    c->b_frame_strategy = 1;
    c->max_b_frames=0;
    c->max_b_frames = 0;

    c->pix_fmt = PIX_FMT_YUV420P;
    c->rc_max_rate = 400000;
    c->refs = 1;

    // Defaults from ffmpeg.c
    c->qblur = 0.5;
    c->qcompress = 0.5;
    c->b_quant_offset = 1.25;
    c->b_quant_factor = 1.25;
    c->i_quant_offset = 0.0;
    c->i_quant_factor = -0.71;

    /*
    // codec flags
    c->flags |= CODEC_FLAG_QSCALE;
    c->flags |= CODEC_FLAG_GLOBAL_HEADER;
    c->flags |= 0;
    c->flags |= 0;
    c->flags |= 0;
    c->flags |= 0;
    c->flags |= 0;
*/

    c->mb_qmax = c->qmax = 51;
    c->mb_qmin = c->qmin = 10;
    c->mb_qmin = c->max_qdiff = 4;
    c->qcompress = 0.6;
    c->me_range = 16;

    c->coder_type = 1;
    c->thread_count = 2;

}

int main(int argc, char** argv)
{
    std::cout.precision(8);
    int program = -1;

    int opt;
    while ((opt = getopt (argc, argv, "i:p:")) != -1) {
        switch (opt) {
        case 'i':
            filename = optarg;
            break;
        case 'p':
            program = atoi(optarg);
            break;
        default:
            goto usage;
            break;
        }
    }

    if (argc < 3) {
        usage:
        std::cerr << "Usage" << std::endl;
        std::cerr << argv[0] << " -i filename [options]" << std::endl;
        std::cerr << " -i Filename" << std::endl;
        return 1;
    }
        int i;
    const int bufsize = 188*40;

    av_register_all();

    AVProbeData   pd;
    AVInputFormat *fmt;

    unsigned char buffer[bufsize];
    unsigned char buffer_out[bufsize];

    IO_read_packet(0, buffer, bufsize);

    pd.filename = ".ts";
    pd.buf = buffer;
    pd.buf_size = bufsize;

    if( !( fmt = av_probe_input_format( &pd, 1 ) ) )
    {
        DEBUG << "Can't find format" << endlog;
        return 0;
    }

    DEBUG << "Name: " << fmt->name << endlog;

    AVFormatContext* ic;
    ByteIOContext io;
    ByteIOContext io_out;

    init_put_byte( &io, buffer, bufsize, 0, NULL, IO_read_packet, 0, 0 );
    init_put_byte( &io_out, buffer_out, bufsize, 0, 0, 0, IO_write_packet, 0
);


    AVFormatParameters params, *ap = &params;
    memset(ap, 0, sizeof(*ap));
    ap->time_base.num = 1;
    ap->time_base.den = 25;


    DEBUG << "Opening stream" << endlog;

    if( av_open_input_stream( &ic, &io, "",
                              fmt, ap ) )
    {
        DEBUG << "Can't open input stream " << endlog;
        return 0;

    }

    std::string streamFmt = fmt->name;
    if (streamFmt != "mpegts")
    {
        DEBUG << "Stream format is not mpeg2ts" << endlog;
        return 0;

    }


    dump_format(ic, 0, "", 0);


    if (program == -1) return 0;

    if( av_find_stream_info( ic ) < 0 )
    {
        DEBUG << "Can not find stream info " << __LINE__ << endlog;
        return 0;
    }


    AVCodecContext* audioContext = 0;
    AVCodecContext* videoContext = 0;
    int audio = -1;
    int video = -1;


    DEBUG << "Number of programs = "  << ic->nb_programs << endlog;
    AVProgram* prg = 0;
    for( i = 0; i < ic->nb_programs; i++ )
    {
        prg = ic->programs[i];
        if (prg->id == program)
            break;
        prg = 0;
    }

    if (!prg)
    {
        DEBUG << "Can't find program @ " << __LINE__ << endlog;
        return 0;
    }

    DEBUG << "Selected Program: " << prg->id << endlog;

    for( i = 0; i < prg->nb_stream_indexes; i++ )
    {
        int index = prg->stream_index[i];
        DEBUG << "Stream: " << index << " ";
        AVCodecContext *cc = ic->streams[index]->codec;

        switch( cc->codec_type )
        {
        case CODEC_TYPE_AUDIO:
            DEBUG << "Audio" << endlog;
            if (audio == -1)
            {
                audioContext = cc;
                audio = index;
                DEBUG << "Audio Selected" << endlog;
            }
            break;
        case CODEC_TYPE_SUBTITLE:
            DEBUG << "Subtitle" << endlog;
            break;
        case CODEC_TYPE_VIDEO:
            DEBUG << "Video Selected" << endlog;
            video = index;
            videoContext = cc;
            g_width = cc->width;
            g_height = cc->height;
            break;
       default:
           DEBUG << "Unknown" << endlog;
           break;

        }
        DEBUG << "   | Codec        " << cc->codec_name << endlog;
        DEBUG << "   | Size         " << cc->width << " x " << cc->height <<
endlog;
        DEBUG << "   | gop_size     " << cc->gop_size << endlog;
        DEBUG << "   | Bitrate      " << cc->bit_rate << endlog;
        DEBUG << "   | Sample Rate  " << cc->sample_rate << endlog;
        DEBUG << "   | Channels     " << cc->channels << endlog;
        DEBUG << "   | Frame Number " << cc-> frame_number  << endlog;
    }


    //
    // Open Video and audio decoders
    //
    AVCodec* pVideoDecoder = 0;
    AVCodec* pAudioDecoder = 0;

    if(videoContext)
    {
        pVideoDecoder = avcodec_find_decoder(videoContext->codec_id);
        if (!pVideoDecoder)
        {
            DEBUG << "Can't find decoder @ " << __LINE__ << endlog;
            return 0;
        }

        if(avcodec_open(videoContext, pVideoDecoder)<0)
        {
            DEBUG << "Can't do something on line " << __LINE__ << endlog;
            return 0;
        }
        DEBUG << "Video Decoder " << pVideoDecoder->name << endlog;
    }

    if (audioContext)
    {
        pAudioDecoder = avcodec_find_decoder(audioContext->codec_id);
        if (!pAudioDecoder)
        {
            DEBUG << "Can't find decoder @ " << __LINE__ << endlog;
            return 0;
        }

        if(avcodec_open(audioContext, pAudioDecoder)<0)
        {
            DEBUG << "Can't do something on line " << __LINE__ << endlog;
            return 0;
        }
        DEBUG << "Audio Decoder " << pAudioDecoder->name << endlog;
    }

    //
    // Allocate frames
    //

    AVPacket    pkt;
    AVFrame videoFrame;

    short* pAudioFrame= (short*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);


    //
    //Allocate output
    //
    AVFormatContext*    outputFormatContext = av_alloc_format_context();
    AVOutputFormat*     ofmt = guess_format( "mpegts", NULL, NULL );

    if (!ofmt)
    {
      DEBUG << "unable for find a suitable output format" << endlog;
      return 0;
    }

    outputFormatContext->oformat = ofmt;
    outputFormatContext->pb = &io_out;

    //
    // Add video stream
    //

    AVStream* stream = av_new_stream(outputFormatContext, 0);
    AVCodecContext* videoEncoderContext = stream->codec;
    setupVideoEncode(videoEncoderContext);
    stream->sample_aspect_ratio = av_d2q(1, 255);
    stream->pts_wrap_bits = 33;
    stream->codec->thread_count = 0;


    //
    // Set output parameters
    //

    if (av_set_parameters(outputFormatContext, 0) < 0) {
        DEBUG << "Can't do something on line " << __LINE__ << endlog;
        return 0;
    }

    //
    // Open video encoder
    //
    AVCodec* codec = avcodec_find_encoder(videoEncoderContext->codec_id);
    if (!codec)
    {
        DEBUG << "Can't do something on line " << __LINE__ << endlog;
        return 0;
    }

    if (avcodec_open(videoEncoderContext, codec) < 0)
    {
        DEBUG << "Can't do something on line " << __LINE__ << endlog;
        return 0;
    }

    dump_format(outputFormatContext, 0, "", 1);


    // write the stream header, if any
      av_write_header(outputFormatContext);


    //
    // Do the transcoding
    //
    int audioFrameFinished = 0;
    int videoFrameFinished = 0;

    const int outbuf_size = 640000;
    uint8_t outbuf[outbuf_size];
    int64_t lastpts = 0;


    while(av_read_frame( ic, &pkt ) == 0)
    {

         if (video == pkt.stream_index){
            avcodec_get_frame_defaults(&videoFrame);
            avcodec_decode_video(videoContext, &videoFrame,
&videoFrameFinished,
                    pkt.data, pkt.size);
            videoFrame.pts = pkt.dts;


            if (videoFrameFinished)
            {

                int out_size = avcodec_encode_video(videoEncoderContext,
outbuf, outbuf_size, &videoFrame);

                if (out_size > 0)
                {
                    AVPacket outpkt;
                    av_init_packet(&outpkt);

                    outpkt.data = outbuf;
                    outpkt.size = out_size;
                    outpkt.stream_index = 0;
                    outpkt.dts = outpkt.pts =
videoEncoderContext->coded_frame->pts;
                    outpkt.flags |=
(videoEncoderContext->coded_frame->key_frame) ? PKT_FLAG_KEY : 0;


                    DEBUG << " enc frame type" <<
videoEncoderContext->coded_frame->pict_type;
                    DEBUG << " key " <<
videoEncoderContext->coded_frame->key_frame;
                    DEBUG << " pts " <<  std::hex << outpkt.pts;
                    DEBUG << " dts " <<  std::hex << outpkt.dts;
                    DEBUG << " diff " <<  (outpkt.pts - lastpts)/90000.0;
                    DEBUG << " Size " << out_size;
                    DEBUG << endlog;
                    lastpts = outpkt.pts;


                    if (av_write_frame (outputFormatContext, &outpkt) < 0)
                    {
                        DEBUG << "unable to write" << endlog;
                        return 0;
                    }

                }

            }


        }


        av_free_packet( &pkt );
    }
    av_write_trailer(outputFormatContext);

    avcodec_close(videoEncoderContext);
    av_free(videoEncoderContext);
    av_free(pAudioFrame);

    DEBUG << "Done!" << endlog;
    return 0;
}
_______________________________________________
libav-user mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/libav-user

Reply via email to