>
> 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 = ¶ms;
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