Mutex FFMPEG::fflock("FFMPEG::fflock");
-static void ff_err(int ret, const char *msg)
+static void ff_err(int ret, const char *fmt, ...)
{
- char errmsg[BCSTRLEN]; av_strerror(ret, errmsg, sizeof(errmsg));
- fprintf(stderr,"%s: %s\n",msg, errmsg);
+ char msg[BCTEXTLEN];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ char errmsg[BCSTRLEN];
+ av_strerror(ret, errmsg, sizeof(errmsg));
+ fprintf(stderr,_("%s err: %s\n"),msg, errmsg);
}
FFPacket::FFPacket()
if( ret >= 0 ) return 1;
st_eof(1);
if( ret == AVERROR_EOF ) return 0;
- fprintf(stderr, "FFStream::read_packet: av_read_frame failed\n");
+ ff_err(ret, "FFStream::read_packet: av_read_frame failed\n");
flushed = 1;
return -1;
}
if( ret < 0 ) {
if( ret == AVERROR(EAGAIN) ) return 0;
if( ret == AVERROR_EOF ) { st_eof(1); return -1; }
- fprintf(stderr, "FFStream::read_filter: av_buffersink_get_frame failed\n");
+ ff_err(ret, "FFStream::read_filter: av_buffersink_get_frame failed\n");
return ret;
}
return 1;
return ret;
}
+int FFStream::write_packet(FFPacket &pkt)
+{
+ bs_filter(pkt);
+ av_packet_rescale_ts(pkt, st->codec->time_base, st->time_base);
+ pkt->stream_index = st->index;
+ return av_interleaved_write_frame(ffmpeg->fmt_ctx, pkt);
+}
+
+int FFStream::flush()
+{
+ int ret = 0;
+ while( ret >= 0 ) {
+ FFPacket pkt;
+ int got_packet = 0;
+ ret = encode_frame(pkt, 0, got_packet);
+ if( ret < 0 || !got_packet ) break;
+ ret = write_packet(pkt);
+ }
+ if( ret < 0 )
+ ff_err(ret, "FFStream::flush");
+ return ret >= 0 ? 0 : 1;
+}
+
FFAudioStream::FFAudioStream(FFMPEG *ffmpeg, AVStream *strm, int idx)
: FFStream(ffmpeg, strm, idx)
{
int ret = swr_convert(resample_context,
(uint8_t**)&aud_bfr, aud_bfr_sz, (const uint8_t**)data, len);
if( ret < 0 ) {
- fprintf(stderr, "FFAudioStream::load_history: swr_convert failed\n");
+ ff_err(ret, "FFAudioStream::load_history: swr_convert failed\n");
return -1;
}
samples = aud_bfr;
{
int ret = avcodec_decode_audio4(st->codec, frame, &got_frame, ipkt);
if( ret < 0 ) {
- fprintf(stderr, "FFAudioStream::decode_frame: Could not read audio frame\n");
+ ff_err(ret, "FFAudioStream::decode_frame: Could not read audio frame\n");
return -1;
}
return ret;
frame->sample_rate = ctx->sample_rate;
int ret = av_frame_get_buffer(frame, 0);
if (ret < 0)
- fprintf(stderr, "FFAudioStream::init_frame: av_frame_get_buffer failed\n");
+ ff_err(ret, "FFAudioStream::init_frame: av_frame_get_buffer failed\n");
return ret;
}
curr_pos += frame->nb_samples;
}
}
- if( flushed && end_pos > curr_pos ) {
+ if( end_pos > curr_pos ) {
zero(end_pos - curr_pos);
curr_pos = end_pos;
}
(uint8_t **)frame->extended_data, frame_sz,
(const uint8_t **)&bfrp, frame_sz);
if( ret < 0 ) {
- fprintf(stderr, "FFAudioStream::encode: swr_convert failed\n");
+ ff_err(ret, "FFAudioStream::encode: swr_convert failed\n");
break;
}
frm->queue(curr_pos);
return ret >= 0 ? 0 : 1;
}
+int FFAudioStream::encode_frame(FFPacket &pkt, AVFrame *frame, int &got_packet)
+{
+ int ret = avcodec_encode_audio2(st->codec, pkt, frame, &got_packet);
+ if( ret < 0 ) {
+ ff_err(ret, "FFAudioStream::encode_frame: encode audio failed\n");
+ return -1;
+ }
+ return ret;
+}
+
FFVideoStream::FFVideoStream(FFMPEG *ffmpeg, AVStream *strm, int idx)
: FFStream(ffmpeg, strm, idx)
{
{
int ret = avcodec_decode_video2(st->codec, frame, &got_frame, ipkt);
if( ret < 0 ) {
- fprintf(stderr, "FFVideoStream::decode_frame: Could not read video frame\n");
+ ff_err(ret, "FFVideoStream::decode_frame: Could not read video frame\n");
return -1;
}
if( got_frame )
int FFVideoStream::load(VFrame *vframe, int64_t pos)
{
- if( video_seek(pos) < 0 ) return -1;
+ int ret = video_seek(pos);
+ if( ret < 0 ) return -1;
if( !frame && !(frame=av_frame_alloc()) ) {
fprintf(stderr, "FFVideoStream::load: av_frame_alloc failed\n");
return -1;
}
- int ret = 0;
for( int i=0; ret>=0 && !flushed && curr_pos<=pos && i<1000; ++i ) {
ret = read_frame(frame);
}
if( gop < 4 ) gop = 4;
if( gop > 64 ) gop = 64;
if( pos >= curr_pos && pos <= curr_pos + gop ) return 0;
+ if( pos == curr_pos-1 && curr_pos > seek_pos ) return 1;
if( !st->codec || !st->codec->codec ) return -1;
avcodec_flush_buffers(st->codec);
// back up a few frames to read up to current to help repair damages
return ret >= 0 ? 0 : 1;
}
+int FFVideoStream::encode_frame(FFPacket &pkt, AVFrame *frame, int &got_packet)
+{
+ int ret = avcodec_encode_video2(st->codec, pkt, frame, &got_packet);
+ if( ret < 0 ) {
+ ff_err(ret, "FFVideoStream::encode_frame: encode video failed\n");
+ return -1;
+ }
+ return ret;
+}
PixelFormat FFVideoStream::color_model_to_pix_fmt(int color_model)
{
" sws_getCachedContext() failed\n");
return 1;
}
- if( sws_scale(convert_ctx, ip->data, ip->linesize, 0, ih,
- opic.data, opic.linesize) < 0 ) {
- fprintf(stderr, "FFVideoStream::convert_picture_frame: sws_scale() failed\n");
+ int ret = sws_scale(convert_ctx, ip->data, ip->linesize, 0, ih,
+ opic.data, opic.linesize);
+ if( ret < 0 ) {
+ ff_err(ret, "FFVideoStream::convert_picture_frame: sws_scale() failed\n");
return 1;
}
return 0;
" sws_getCachedContext() failed\n");
return 1;
}
- if( sws_scale(convert_ctx, opic.data, opic.linesize, 0, frame->get_h(),
- op->data, op->linesize) < 0 ) {
- fprintf(stderr, "FFVideoStream::convert_frame_picture: sws_scale() failed\n");
+ int ret = sws_scale(convert_ctx, opic.data, opic.linesize, 0, frame->get_h(),
+ op->data, op->linesize);
+ if( ret < 0 ) {
+ ff_err(ret, "FFVideoStream::convert_frame_picture: sws_scale() failed\n");
return 1;
}
return 0;
return (AVRational){1, sample_rate};
}
-extern void get_exe_path(char *result); // from main.C
-
void FFMPEG::set_option_path(char *path, const char *fmt, ...)
{
get_exe_path(path);
return 1;
}
if( get_encoder(fp, format, codec, bsfilter, bsargs) )
- eprintf("FFMPEG::get_encoder:"
- " err: format/codec not found %s\n", options);
+ eprintf(_("FFMPEG::get_encoder:"
+ " err: format/codec not found %s\n"), options);
fclose(fp);
return 0;
}
return ret;
}
-int FFMPEG::scan_options(const char *options, AVDictionary *&opts)
+int FFMPEG::scan_options(const char *options, AVDictionary *&opts, AVStream *st)
{
FILE *fp = fmemopen((void *)options,strlen(options),"r");
if( !fp ) return 0;
int ret = read_options(fp, options, opts);
fclose(fp);
+ AVDictionaryEntry *tag = av_dict_get(opts, "id", NULL, 0);
+ if( tag ) st->id = strtol(tag->value,0,0);
return ret;
}
if( line[0] == '\n' ) continue;
char key[BCSTRLEN], val[BCTEXTLEN];
if( scan_option_line(line, key, val) ) {
- eprintf("FFMPEG::read_options:"
- " err reading %s: line %d\n", options, no);
+ eprintf(_("FFMPEG::read_options:"
+ " err reading %s: line %d\n"), options, no);
ret = 1;
}
if( !ret ) {
for( int i=0; i<(int)fmt_ctx->nb_streams; ++i ) {
AVStream *st = fmt_ctx->streams[i];
AVCodecContext *avctx = st->codec;
- report("stream %d, id 0x%06x:\n", i, avctx->codec_id);
+ report(_("stream %d, id 0x%06x:\n"), i, avctx->codec_id);
const AVCodecDescriptor *desc = avcodec_descriptor_get(avctx->codec_id);
if( avctx->codec_type == AVMEDIA_TYPE_VIDEO ) {
AVRational framerate = av_guess_frame_rate(fmt_ctx, st, 0);
report(" %d:%02d:%05.2f\n", hrs, mins, secs);
}
else
- report(" codec_type unknown\n");
+ report(_(" codec_type unknown\n"));
}
report("\n");
for( int i=0; i<(int)fmt_ctx->nb_programs; ++i ) {
break;
}
has_audio = 1;
- if( scan_options(asset->ff_audio_options, sopts) ) {
+ if( scan_options(asset->ff_audio_options, sopts, st) ) {
eprintf("FFMPEG::open_encoder: bad audio options %s:%s\n",
codec_name, filename);
ret = 1;
break;
}
has_video = 1;
- if( scan_options(asset->ff_video_options, sopts) ) {
+ if( scan_options(asset->ff_video_options, sopts, st) ) {
eprintf("FFMPEG::open_encoder: bad video options %s:%s\n",
codec_name, filename);
ret = 1;
int FFMPEG::encode_activate()
{
+ int ret = 0;
if( encoding < 0 ) {
encoding = 0;
if( !(fmt_ctx->flags & AVFMT_NOFILE) &&
- avio_open(&fmt_ctx->pb, fmt_ctx->filename, AVIO_FLAG_WRITE) < 0 ) {
- fprintf(stderr, "FFMPEG::encode_activate: err opening : %s\n",
+ (ret=avio_open(&fmt_ctx->pb, fmt_ctx->filename, AVIO_FLAG_WRITE)) < 0 ) {
+ ff_err(ret, "FFMPEG::encode_activate: err opening : %s\n",
fmt_ctx->filename);
return 1;
}
char option_path[BCTEXTLEN];
set_option_path(option_path, "format/%s", file_format);
read_options(option_path, fopts);
- int ret = avformat_write_header(fmt_ctx, &fopts);
+ ret = avformat_write_header(fmt_ctx, &fopts);
av_dict_free(&fopts);
if( ret < 0 ) {
- fprintf(stderr, "FFMPEG::encode_activate: write header failed %s\n",
+ ff_err(ret, "FFMPEG::encode_activate: write header failed %s\n",
fmt_ctx->filename);
return 1;
}
int FFMPEG::mux_audio(FFrame *frm)
{
FFPacket pkt;
- AVStream *st = frm->fst->st;
- AVCodecContext *ctx = st->codec;
+ FFStream *fst = frm->fst;
+ AVCodecContext *ctx = fst->st->codec;
AVFrame *frame = *frm;
AVRational tick_rate = {1, ctx->sample_rate};
frame->pts = av_rescale_q(frm->position, tick_rate, ctx->time_base);
int got_packet = 0;
- int ret = avcodec_encode_audio2(ctx, pkt, frame, &got_packet);
- if( ret >= 0 && got_packet ) {
- frm->fst->bs_filter(pkt);
- av_packet_rescale_ts(pkt, ctx->time_base, st->time_base);
- pkt->stream_index = st->index;
- ret = av_interleaved_write_frame(fmt_ctx, pkt);
- }
+ int ret = fst->encode_frame(pkt, frame, got_packet);
+ if( ret >= 0 && got_packet )
+ ret = fst->write_packet(pkt);
if( ret < 0 )
ff_err(ret, "FFMPEG::mux_audio");
return ret >= 0 ? 0 : 1;
int FFMPEG::mux_video(FFrame *frm)
{
FFPacket pkt;
- AVStream *st = frm->fst->st;
+ FFStream *fst = frm->fst;
AVFrame *frame = *frm;
frame->pts = frm->position;
int ret = 1, got_packet = 0;
if( fmt_ctx->oformat->flags & AVFMT_RAWPICTURE ) {
/* a hack to avoid data copy with some raw video muxers */
pkt->flags |= AV_PKT_FLAG_KEY;
- pkt->stream_index = st->index;
+ pkt->stream_index = fst->st->index;
AVPicture *picture = (AVPicture *)frame;
pkt->data = (uint8_t *)picture;
pkt->size = sizeof(AVPicture);
got_packet = 1;
}
else
- ret = avcodec_encode_video2(st->codec, pkt, frame, &got_packet);
- if( ret >= 0 && got_packet ) {
- frm->fst->bs_filter(pkt);
- av_packet_rescale_ts(pkt, st->codec->time_base, st->time_base);
- pkt->stream_index = st->index;
- ret = av_interleaved_write_frame(fmt_ctx, pkt);
- }
+ ret = fst->encode_frame(pkt, frame, got_packet);
+ if( ret >= 0 && got_packet )
+ ret = fst->write_packet(pkt);
if( ret < 0 )
ff_err(ret, "FFMPEG::mux_video");
return ret >= 0 ? 0 : 1;
if( !done ) mux();
}
mux();
+ for( int i=0; i<ffaudio.size(); ++i )
+ ffaudio[i]->flush();
+ for( int i=0; i<ffvideo.size(); ++i )
+ ffvideo[i]->flush();
}