some muxing going on! :D

This commit is contained in:
Themaister 2011-01-04 15:44:05 +01:00
parent 4e77573683
commit 9bbd42166c
3 changed files with 145 additions and 46 deletions

View File

@ -1,5 +1,7 @@
#include <libavcodec/avcodec.h>
#include <libavutil/mathematics.h>
#include <libavutil/avutil.h>
#include <libavutil/avstring.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <stdint.h>
@ -16,14 +18,13 @@ struct video_info
AVFrame *conv_frame;
uint8_t *conv_frame_buf;
int64_t frame_count;
FILE *file;
char *file_name;
int64_t frame_cnt;
uint8_t *outbuf;
size_t outbuf_size;
AVFormatContext *format;
} video;
struct audio_info
@ -36,15 +37,20 @@ struct audio_info
void *outbuf;
size_t outbuf_size;
FILE *file;
char *file_name;
} audio;
struct muxer_info
{
AVFormatContext *ctx;
AVStream *astream;
AVStream *vstream;
};
struct ffemu
{
struct video_info video;
struct audio_info audio;
struct muxer_info muxer;
struct ffemu_params params;
};
@ -58,7 +64,7 @@ static int map_audio_codec(ffemu_audio_codec codec)
static int map_video_codec(ffemu_video_codec codec)
{
(void)codec;
return CODEC_ID_MPEG2VIDEO;
return CODEC_ID_H264;
}
static int init_audio(struct audio_info *audio, struct ffemu_params *param)
@ -68,7 +74,7 @@ static int init_audio(struct audio_info *audio, struct ffemu_params *param)
return -1;
audio->codec = avcodec_alloc_context();
audio->codec->bit_rate = 128000;
audio->codec->bit_rate = 192000;
audio->codec->sample_rate = param->samplerate;
audio->codec->channels = param->channels;
@ -79,10 +85,6 @@ static int init_audio(struct audio_info *audio, struct ffemu_params *param)
if (!audio->buffer)
return -1;
audio->file = fopen("/tmp/audio.aac", "wb");
if (!audio->file)
return -1;
audio->outbuf_size = 50000;
audio->outbuf = av_malloc(audio->outbuf_size);
if (!audio->outbuf)
@ -91,6 +93,35 @@ static int init_audio(struct audio_info *audio, struct ffemu_params *param)
return 0;
}
static void init_x264_param(AVCodecContext *c)
{
c->coder_type = 1; // coder = 1
c->flags|=CODEC_FLAG_LOOP_FILTER; // flags=+loop
c->me_cmp|= 1; // cmp=+chroma, where CHROMA = 1
c->partitions|=X264_PART_I8X8+X264_PART_I4X4+X264_PART_P8X8+X264_PART_B8X8; // partitions=+parti8x8+parti4x4+partp8x8+partb8x8
c->me_method=ME_HEX; // me_method=hex
c->me_subpel_quality = 7; // subq=7
c->me_range = 16; // me_range=16
c->gop_size = 250; // g=250
c->keyint_min = 25; // keyint_min=25
c->scenechange_threshold = 40; // sc_threshold=40
c->i_quant_factor = 0.71; // i_qfactor=0.71
c->b_frame_strategy = 1; // b_strategy=1
c->qcompress = 0.6; // qcomp=0.6
c->qmin = 10; // qmin=10
c->qmax = 51; // qmax=51
c->max_qdiff = 4; // qdiff=4
c->max_b_frames = 3; // bf=3
c->refs = 3; // refs=3
c->directpred = 1; // directpred=1
c->trellis = 1; // trellis=1
c->flags2|=CODEC_FLAG2_BPYRAMID+CODEC_FLAG2_MIXED_REFS+CODEC_FLAG2_WPRED+CODEC_FLAG2_8X8DCT+CODEC_FLAG2_FASTPSKIP; // flags2=+bpyramid+mixed_refs+wpred+dct8x8+fastpskip
c->weighted_p_pred = 2; // wpredp=2
// libx264-main.ffpreset preset
c->flags2|=CODEC_FLAG2_8X8DCT;c->flags2^=CODEC_FLAG2_8X8DCT;
}
static int init_video(struct video_info *video, struct ffemu_params *param)
{
AVCodec *codec = avcodec_find_encoder(map_video_codec(param->vcodec));
@ -98,13 +129,12 @@ static int init_video(struct video_info *video, struct ffemu_params *param)
return -1;
video->codec = avcodec_alloc_context();
video->codec->bit_rate = 400000;
video->codec->width = param->out_width;
video->codec->height = param->out_height;
video->codec->time_base = (AVRational) {param->fps.den, param->fps.num};
video->codec->gop_size = 10;
video->codec->max_b_frames = 1;
video->codec->crf = 23;
video->codec->pix_fmt = PIX_FMT_YUV420P;
init_x264_param(video->codec);
if (avcodec_open(video->codec, codec) != 0)
return -1;
@ -117,8 +147,45 @@ static int init_video(struct video_info *video, struct ffemu_params *param)
video->conv_frame = avcodec_alloc_frame();
avpicture_fill((AVPicture*)video->conv_frame, video->conv_frame_buf, PIX_FMT_YUV420P, param->out_width, param->out_height);
video->file = fopen("/tmp/video.mpg", "wb");
return 0;
}
static int init_muxer(ffemu_t *handle)
{
AVFormatContext *ctx = avformat_alloc_context();
av_strlcpy(ctx->filename, handle->params.filename, sizeof(ctx->filename));
ctx->oformat = av_guess_format(NULL, ctx->filename, NULL);
if (url_fopen(&ctx->pb, ctx->filename, URL_WRONLY) < 0)
{
av_free(ctx);
return -1;
}
int stream_cnt = 0;
if (handle->video.enabled)
{
AVStream *stream = av_new_stream(ctx, stream_cnt++);
stream->codec = handle->video.codec;
if (ctx->oformat->flags & AVFMT_GLOBALHEADER)
handle->video.codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
handle->muxer.vstream = stream;
}
if (handle->audio.enabled)
{
AVStream *stream = av_new_stream(ctx, stream_cnt++);
stream->codec = handle->audio.codec;
if (ctx->oformat->flags & AVFMT_GLOBALHEADER)
handle->audio.codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
handle->muxer.astream = stream;
}
if (av_write_header(ctx) < 0)
return -1;
handle->muxer.ctx = ctx;
return 0;
}
@ -145,6 +212,9 @@ ffemu_t *ffemu_new(const struct ffemu_params *params)
if (init_audio(&handle->audio, &handle->params) < 0)
goto error;
if (init_muxer(handle) < 0)
goto error;
return handle;
error:
@ -177,11 +247,6 @@ void ffemu_free(ffemu_t *handle)
if (handle->video.conv_frame_buf)
av_free(handle->video.conv_frame_buf);
if (handle->video.file)
fclose(handle->video.file);
if (handle->audio.file)
fclose(handle->audio.file);
free(handle);
}
}
@ -199,16 +264,23 @@ int ffemu_push_video(ffemu_t *handle, const struct ffemu_video_data *data)
sws_scale(conv_ctx, (const uint8_t* const*)&data->data, &linesize, 0, handle->params.out_width, handle->video.conv_frame->data, handle->video.conv_frame->linesize);
handle->video.conv_frame->pts = handle->video.frame_count;
handle->video.conv_frame->display_picture_number = handle->video.frame_count;
handle->video.frame_count++;
int outsize = avcodec_encode_video(handle->video.codec, handle->video.outbuf, handle->video.outbuf_size, handle->video.conv_frame);
fwrite(handle->video.outbuf, 1, outsize, handle->video.file);
//fwrite(handle->video.outbuf, 1, outsize, handle->video.file);
sws_freeContext(conv_ctx);
AVPacket pkt;
av_init_packet(&pkt);
pkt.stream_index = handle->muxer.vstream->index;
pkt.data = handle->video.outbuf;
pkt.size = outsize;
pkt.pts = av_rescale_q(handle->video.frame_cnt++, handle->video.codec->time_base, handle->muxer.vstream->time_base);
pkt.dts = pkt.pts;
if (av_interleaved_write_frame(handle->muxer.ctx, &pkt) < 0)
return -1;
return 0;
}
@ -217,6 +289,13 @@ int ffemu_push_audio(ffemu_t *handle, const struct ffemu_audio_data *data)
if (!handle->audio.enabled)
return -1;
AVPacket pkt;
av_init_packet(&pkt);
pkt.stream_index = handle->muxer.astream->index;
pkt.pts = AV_NOPTS_VALUE;
pkt.dts = pkt.pts;
pkt.data = handle->audio.outbuf;
size_t written_frames = 0;
while (written_frames < data->frames)
{
@ -233,18 +312,45 @@ int ffemu_push_audio(ffemu_t *handle, const struct ffemu_audio_data *data)
if (handle->audio.frames_in_buffer == (size_t)handle->audio.codec->frame_size)
{
size_t out_size = avcodec_encode_audio(handle->audio.codec, handle->audio.outbuf, handle->audio.outbuf_size, handle->audio.buffer);
fwrite(handle->audio.outbuf, 1, out_size, handle->audio.file);
//fwrite(handle->audio.outbuf, 1, out_size, handle->audio.file);
pkt.size = out_size;
handle->audio.frames_in_buffer = 0;
if (av_interleaved_write_frame(handle->muxer.ctx, &pkt) < 0)
return -1;
}
}
return 0;
}
int ffemu_mux(ffemu_t *handle, const char *path, const struct ffemu_muxer *muxer)
int ffemu_finalize(ffemu_t *handle)
{
(void)handle;
(void)path;
(void)muxer;
return -1;
// Push out delayed frames.
if (handle->video.enabled)
{
AVPacket pkt;
av_init_packet(&pkt);
pkt.stream_index = handle->muxer.vstream->index;
pkt.data = handle->video.outbuf;
int out_size = 0;
do
{
out_size = avcodec_encode_video(handle->video.codec, handle->video.outbuf, handle->video.outbuf_size, NULL);
pkt.size = out_size;
pkt.pts = av_rescale_q(handle->video.frame_cnt++, handle->video.codec->time_base, handle->muxer.vstream->time_base);
pkt.dts = pkt.pts;
int err = av_interleaved_write_frame(handle->muxer.ctx, &pkt);
if (err < 0)
break;
} while (out_size > 0);
}
av_write_trailer(handle->muxer.ctx);
return 0;
}

View File

@ -32,13 +32,6 @@ typedef enum ffemu_pixel_format
FFEMU_FMT_RGB888,
} ffemu_pixel_format;
// Available muxer containers
typedef enum ffemu_container
{
FFEMU_CONTAINER_MKV,
FFEMU_CONTAINER_MP4
} ffemu_container;
struct ffemu_rational
{
unsigned num;
@ -88,6 +81,9 @@ struct ffemu_params
// Define some audio codec dependent option.
uint64_t audio_opt;
// Filename to dump to.
const char *filename;
};
struct ffemu_video_data
@ -104,11 +100,6 @@ struct ffemu_audio_data
size_t frames;
};
struct ffemu_muxer
{
ffemu_container container;
};
typedef struct ffemu ffemu_t;
ffemu_t *ffemu_new(const struct ffemu_params *params);
@ -116,8 +107,8 @@ void ffemu_free(ffemu_t* handle);
int ffemu_push_video(ffemu_t *handle, const struct ffemu_video_data *data);
int ffemu_push_audio(ffemu_t *handle, const struct ffemu_audio_data *data);
int ffemu_finalize(ffemu_t *handle);
int ffemu_mux(ffemu_t *handle, const char *path, const struct ffemu_muxer *muxer);
#ifdef __cplusplus

View File

@ -366,6 +366,7 @@ int main(int argc, char *argv[])
.out_height = 448,
.channels = 2,
.samplerate = 32040,
.filename = "/tmp/ssnes.mkv",
.fps = {60000, 1001},
.aspect_ratio = 4.0/3
};
@ -400,6 +401,7 @@ int main(int argc, char *argv[])
}
///////////
ffemu_finalize(g_extern.rec);
ffemu_free(g_extern.rec);
///////////