summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2011-08-18 10:20:25 +0200
committerMichael Niedermayer <michaelni@gmx.at>2011-08-18 10:56:08 +0200
commitedae3dbf1d9d7d76af961914c07998eb7bbb482b (patch)
treecaded6febf91793f858df78f1f7bed6430c88c5e
parent2f53fce3b193beeffdcd1ecf1bf7c80a4e3dc388 (diff)
parentb490f0c2bcec9d66d8878187f7e6661017e6d398 (diff)
Merge remote-tracking branch 'qatar/master'
* qatar/master: (23 commits) h264: hide reference frame errors unless requested swscale: split hScale() function pointer into h[cy]Scale(). Move clipd macros to x86util.asm. avconv: reindent. avconv: rescue poor abused start_time global. avconv: rescue poor abused recording_time global. avconv: merge two loops in output_packet(). avconv: fix broken indentation. avconv: get rid of the arbitrary MAX_FILES limit. avconv: get rid of the output_streams_for_file vs. ost_table schizophrenia avconv: add a wrapper for output AVFormatContexts and merge output_opts into it avconv: make itsscale syntax consistent with other options. avconv: factor out adding input streams. avconv: Factorize combining auto vsync with format. avconv: Factorize video resampling. avconv: Don't unnecessarily convert ipts to a double. ffmpeg: remove unsed variable nopts RV3/4 parser: remove unused variable 'off' add XMV demuxer rmdec: parse FPS in RealMedia properly ... Conflicts: avconv.c libavformat/version.h libswscale/swscale.c tests/ref/fate/lmlm4-demux Merged-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r--Changelog1
-rw-r--r--avconv.c790
-rw-r--r--doc/general.texi2
-rw-r--r--ffmpeg.c23
-rw-r--r--libavcodec/Makefile2
-rw-r--r--libavcodec/allcodecs.c2
-rw-r--r--libavcodec/h264_refs.c2
-rw-r--r--libavcodec/rv34_parser.c95
-rw-r--r--libavcodec/x86/dsputil_yasm.asm34
-rw-r--r--libavformat/Makefile1
-rw-r--r--libavformat/allformats.c1
-rw-r--r--libavformat/rmdec.c28
-rw-r--r--libavformat/version.h2
-rw-r--r--libavformat/xmv.c576
-rw-r--r--libavutil/x86/x86util.asm33
-rw-r--r--libswscale/ppc/swscale_altivec.c2
-rw-r--r--libswscale/swscale.c12
-rw-r--r--libswscale/swscale_internal.h11
-rw-r--r--libswscale/x86/swscale_template.c2
-rw-r--r--tests/ref/fate/feeble-dxa1
-rw-r--r--tests/ref/fate/lmlm4-demux1
-rw-r--r--tests/ref/fate/real-rv40359
-rw-r--r--tests/ref/fate/rv30153
23 files changed, 1485 insertions, 648 deletions
diff --git a/Changelog b/Changelog
index caf9a53cc8..fd5863d2ff 100644
--- a/Changelog
+++ b/Changelog
@@ -41,6 +41,7 @@ easier to use. The changes are:
* Presets in avconv are disabled, because only libx264 used them and
presets for libx264 can now be specified using a private option
'-preset <presetname>'.
+- XMV demuxer
version 0.8:
diff --git a/avconv.c b/avconv.c
index c86e16bed9..85937fc365 100644
--- a/avconv.c
+++ b/avconv.c
@@ -109,15 +109,9 @@ typedef struct MetadataMap {
static const OptionDef options[];
-#define MAX_FILES 100
#define MAX_STREAMS 1024 /* arbitrary sanity check value */
static const char *last_asked_format = NULL;
-static double *ts_scale;
-static int nb_ts_scale;
-
-static AVFormatContext *output_files[MAX_FILES];
-static AVDictionary *output_opts[MAX_FILES];
-static int nb_output_files = 0;
+static AVDictionary *ts_scale;
static StreamMap *stream_maps = NULL;
static int nb_stream_maps;
@@ -294,11 +288,9 @@ typedef struct OutputStream {
int sws_flags;
AVDictionary *opts;
+ int is_past_recording_time;
} OutputStream;
-static OutputStream **output_streams_for_file[MAX_FILES] = { NULL };
-static int nb_output_streams_for_file[MAX_FILES] = { 0 };
-
typedef struct InputStream {
int file_index;
AVStream *st;
@@ -313,7 +305,6 @@ typedef struct InputStream {
double ts_scale;
int is_start; /* is 1 at the start and after a discontinuity */
int showed_multi_packet_warning;
- int is_past_recording_time;
AVDictionary *opts;
} InputStream;
@@ -332,11 +323,24 @@ typedef struct InputFile {
static struct termios oldtty;
#endif
+typedef struct OutputFile {
+ AVFormatContext *ctx;
+ AVDictionary *opts;
+ int ost_index; /* index of the first stream in output_streams */
+ int64_t recording_time; /* desired length of the resulting file in microseconds */
+ int64_t start_time; /* start time in microseconds */
+} OutputFile;
+
static InputStream *input_streams = NULL;
static int nb_input_streams = 0;
static InputFile *input_files = NULL;
static int nb_input_files = 0;
+static OutputStream *output_streams = NULL;
+static int nb_output_streams = 0;
+static OutputFile *output_files = NULL;
+static int nb_output_files = 0;
+
#if CONFIG_AVFILTER
static int configure_video_filters(InputStream *ist, OutputStream *ost)
@@ -516,12 +520,11 @@ static int exit_program(int ret)
/* close files */
for(i=0;i<nb_output_files;i++) {
- AVFormatContext *s = output_files[i];
+ AVFormatContext *s = output_files[i].ctx;
if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
avio_close(s->pb);
avformat_free_context(s);
- av_free(output_streams_for_file[i]);
- av_dict_free(&output_opts[i]);
+ av_dict_free(&output_files[i].opts);
}
for(i=0;i<nb_input_files;i++) {
av_close_input_file(input_files[i].ctx);
@@ -541,6 +544,8 @@ static int exit_program(int ret)
av_freep(&input_streams);
av_freep(&input_files);
+ av_freep(&output_streams);
+ av_freep(&output_files);
uninit_opts();
av_free(audio_buf);
@@ -682,7 +687,8 @@ static double
get_sync_ipts(const OutputStream *ost)
{
const InputStream *ist = ost->sync_ist;
- return (double)(ist->pts - start_time)/AV_TIME_BASE;
+ OutputFile *of = &output_files[ost->file_index];
+ return (double)(ist->pts - of->start_time)/AV_TIME_BASE;
}
static void write_frame(AVFormatContext *s, AVPacket *pkt, AVCodecContext *avctx, AVBitStreamFilterContext *bsfc){
@@ -1071,58 +1077,14 @@ static void do_subtitle_out(AVFormatContext *s,
static int bit_buffer_size= 1024*256;
static uint8_t *bit_buffer= NULL;
-static void do_video_out(AVFormatContext *s,
- OutputStream *ost,
- InputStream *ist,
- AVFrame *in_picture,
- int *frame_size, float quality)
+static void do_video_resample(OutputStream *ost,
+ InputStream *ist,
+ AVFrame *in_picture,
+ AVFrame **out_picture)
{
- int nb_frames, i, ret, av_unused resample_changed;
- AVFrame *final_picture, *formatted_picture;
- AVCodecContext *enc, *dec;
- double sync_ipts;
-
- enc = ost->st->codec;
- dec = ist->st->codec;
-
- sync_ipts = get_sync_ipts(ost) / av_q2d(enc->time_base);
-
- /* by default, we output a single frame */
- nb_frames = 1;
-
- *frame_size = 0;
-
- if(video_sync_method){
- double vdelta = sync_ipts - ost->sync_opts;
- //FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
- if (vdelta < -1.1)
- nb_frames = 0;
- else if (video_sync_method == 2 || (video_sync_method<0 && (s->oformat->flags & AVFMT_VARIABLE_FPS))){
- if(vdelta<=-0.6){
- nb_frames=0;
- }else if(vdelta>0.6)
- ost->sync_opts= lrintf(sync_ipts);
- }else if (vdelta > 1.1)
- nb_frames = lrintf(vdelta);
-//fprintf(stderr, "vdelta:%f, ost->sync_opts:%"PRId64", ost->sync_ipts:%f nb_frames:%d\n", vdelta, ost->sync_opts, get_sync_ipts(ost), nb_frames);
- if (nb_frames == 0){
- ++nb_frames_drop;
- if (verbose>2)
- fprintf(stderr, "*** drop!\n");
- }else if (nb_frames > 1) {
- nb_frames_dup += nb_frames - 1;
- if (verbose>2)
- fprintf(stderr, "*** %d dup!\n", nb_frames-1);
- }
- }else
- ost->sync_opts= lrintf(sync_ipts);
-
- nb_frames= FFMIN(nb_frames, max_frames[AVMEDIA_TYPE_VIDEO] - ost->frame_number);
- if (nb_frames <= 0)
- return;
-
- formatted_picture = in_picture;
- final_picture = formatted_picture;
+ int resample_changed = 0;
+ AVCodecContext *dec = ist->st->codec;
+ *out_picture = in_picture;
resample_changed = ost->resample_width != dec->width ||
ost->resample_height != dec->height ||
@@ -1145,7 +1107,7 @@ static void do_video_out(AVFormatContext *s,
dec->pix_fmt != enc->pix_fmt;
if (ost->video_resample) {
- final_picture = &ost->resample_frame;
+ *out_picture = &ost->resample_frame;
if (!ost->img_resample_ctx || resample_changed) {
/* initialize the destination picture */
if (!ost->resample_frame.data[0]) {
@@ -1166,8 +1128,8 @@ static void do_video_out(AVFormatContext *s,
exit_program(1);
}
}
- sws_scale(ost->img_resample_ctx, formatted_picture->data, formatted_picture->linesize,
- 0, ost->resample_height, final_picture->data, final_picture->linesize);
+ sws_scale(ost->img_resample_ctx, in_picture->data, in_picture->linesize,
+ 0, ost->resample_height, (*out_picture)->data, (*out_picture)->linesize);
}
#else
if (resample_changed) {
@@ -1183,6 +1145,64 @@ static void do_video_out(AVFormatContext *s,
ost->resample_height = dec->height;
ost->resample_pix_fmt = dec->pix_fmt;
}
+}
+
+
+static void do_video_out(AVFormatContext *s,
+ OutputStream *ost,
+ InputStream *ist,
+ AVFrame *in_picture,
+ int *frame_size, float quality)
+{
+ int nb_frames, i, ret, format_video_sync;
+ AVFrame *final_picture;
+ AVCodecContext *enc, *dec;
+ double sync_ipts;
+
+ enc = ost->st->codec;
+ dec = ist->st->codec;
+
+ sync_ipts = get_sync_ipts(ost) / av_q2d(enc->time_base);
+
+ /* by default, we output a single frame */
+ nb_frames = 1;
+
+ *frame_size = 0;
+
+ format_video_sync = video_sync_method;
+ if (format_video_sync < 0)
+ format_video_sync = (s->oformat->flags & AVFMT_VARIABLE_FPS) ? 2 : 1;
+
+ if (format_video_sync) {
+ double vdelta = sync_ipts - ost->sync_opts;
+ //FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
+ if (vdelta < -1.1)
+ nb_frames = 0;
+ else if (format_video_sync == 2) {
+ if(vdelta<=-0.6){
+ nb_frames=0;
+ }else if(vdelta>0.6)
+ ost->sync_opts= lrintf(sync_ipts);
+ }else if (vdelta > 1.1)
+ nb_frames = lrintf(vdelta);
+//fprintf(stderr, "vdelta:%f, ost->sync_opts:%"PRId64", ost->sync_ipts:%f nb_frames:%d\n", vdelta, ost->sync_opts, get_sync_ipts(ost), nb_frames);
+ if (nb_frames == 0){
+ ++nb_frames_drop;
+ if (verbose>2)
+ fprintf(stderr, "*** drop!\n");
+ }else if (nb_frames > 1) {
+ nb_frames_dup += nb_frames - 1;
+ if (verbose>2)
+ fprintf(stderr, "*** %d dup!\n", nb_frames-1);
+ }
+ }else
+ ost->sync_opts= lrintf(sync_ipts);
+
+ nb_frames= FFMIN(nb_frames, max_frames[AVMEDIA_TYPE_VIDEO] - ost->frame_number);
+ if (nb_frames <= 0)
+ return;
+
+ do_video_resample(ost, ist, in_picture, &final_picture);
/* duplicates frame if needed */
for(i=0;i<nb_frames;i++) {
@@ -1307,8 +1327,8 @@ static void do_video_stats(AVFormatContext *os, OutputStream *ost,
}
}
-static void print_report(AVFormatContext **output_files,
- OutputStream **ost_table, int nb_ostreams,
+static void print_report(OutputFile *output_files,
+ OutputStream *ost_table, int nb_ostreams,
int is_last_report)
{
char buf[1024];
@@ -1336,7 +1356,7 @@ static void print_report(AVFormatContext **output_files,
}
- oc = output_files[0];
+ oc = output_files[0].ctx;
total_size = avio_size(oc->pb);
if(total_size<0) // FIXME improve avio_size() so it works with non seekable output too
@@ -1346,7 +1366,7 @@ static void print_report(AVFormatContext **output_files,
vid = 0;
for(i=0;i<nb_ostreams;i++) {
float q = -1;
- ost = ost_table[i];
+ ost = &ost_table[i];
enc = ost->st->codec;
if (!ost->st->stream_copy && enc->coded_frame)
q = enc->coded_frame->quality/(float)FF_QP2LAMBDA;
@@ -1448,7 +1468,7 @@ static void generate_silence(uint8_t* buf, enum AVSampleFormat sample_fmt, size_
/* pkt = NULL means EOF (needed to flush decoder buffers) */
static int output_packet(InputStream *ist, int ist_index,
- OutputStream **ost_table, int nb_ostreams,
+ OutputStream *ost_table, int nb_ostreams,
const AVPacket *pkt)
{
AVFormatContext *os;
@@ -1595,22 +1615,6 @@ static int output_packet(InputStream *ist, int ist_index,
avpkt.size = 0;
}
-#if CONFIG_AVFILTER
- if(ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
- if (start_time == 0 || ist->pts >= start_time) {
- for(i=0;i<nb_ostreams;i++) {
- ost = ost_table[i];
- if (ost->input_video_filter && ost->source_index == ist_index) {
- if (!picture.sample_aspect_ratio.num)
- picture.sample_aspect_ratio = ist->st->sample_aspect_ratio;
- picture.pts = ist->pts;
-
- av_vsrc_buffer_add_frame(ost->input_video_filter, &picture, AV_VSRC_BUF_FLAG_OVERWRITE);
- }
- }
- }
-#endif
-
// preprocess audio (volume)
if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
if (audio_volume != 256) {
@@ -1634,130 +1638,149 @@ static int output_packet(InputStream *ist, int ist_index,
}
/* if output time reached then transcode raw format,
encode packets and output them */
- if (start_time == 0 || ist->pts >= start_time)
- for(i=0;i<nb_ostreams;i++) {
- int frame_size;
+ for (i = 0; i < nb_ostreams; i++) {
+ OutputFile *of = &output_files[ost_table[i].file_index];
+ int frame_size;
+
+ ost = &ost_table[i];
+ if (ost->source_index != ist_index)
+ continue;
+
+ if (of->start_time && ist->pts < of->start_time)
+ continue;
+
+ if (of->recording_time != INT64_MAX &&
+ av_compare_ts(ist->pts, AV_TIME_BASE_Q, of->recording_time + of->start_time,
+ (AVRational){1, 1000000}) >= 0) {
+ ost->is_past_recording_time = 1;
+ continue;
+ }
- ost = ost_table[i];
- if (ost->source_index == ist_index) {
#if CONFIG_AVFILTER
- frame_available = ist->st->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
- !ost->output_video_filter || avfilter_poll_frame(ost->output_video_filter->inputs[0]);
- while (frame_available) {
- if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && ost->output_video_filter) {
- AVRational ist_pts_tb = ost->output_video_filter->inputs[0]->time_base;
- if (av_vsink_buffer_get_video_buffer_ref(ost->output_video_filter, &ost->picref, 0) < 0)
- goto cont;
- if (ost->picref) {
- avfilter_fill_frame_from_video_buffer_ref(&picture, ost->picref);
- ist->pts = av_rescale_q(ost->picref->pts, ist_pts_tb, AV_TIME_BASE_Q);
- }
+ if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+ ost->input_video_filter) {
+ if (!picture.sample_aspect_ratio.num)
+ picture.sample_aspect_ratio = ist->st->sample_aspect_ratio;
+ picture.pts = ist->pts;
+
+ av_vsrc_buffer_add_frame(ost->input_video_filter, &picture, AV_VSRC_BUF_FLAG_OVERWRITE);
+ }
+ frame_available = ist->st->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
+ !ost->output_video_filter || avfilter_poll_frame(ost->output_video_filter->inputs[0]);
+ while (frame_available) {
+ if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && ost->output_video_filter) {
+ AVRational ist_pts_tb = ost->output_video_filter->inputs[0]->time_base;
+ if (av_vsink_buffer_get_video_buffer_ref(ost->output_video_filter, &ost->picref, 0) < 0)
+ goto cont;
+ if (ost->picref) {
+ avfilter_fill_frame_from_video_buffer_ref(&picture, ost->picref);
+ ist->pts = av_rescale_q(ost->picref->pts, ist_pts_tb, AV_TIME_BASE_Q);
}
+ }
#endif
- os = output_files[ost->file_index];
+ os = output_files[ost->file_index].ctx;
- /* set the input output pts pairs */
- //ost->sync_ipts = (double)(ist->pts + input_files[ist->file_index].ts_offset - start_time)/ AV_TIME_BASE;
+ /* set the input output pts pairs */
+ //ost->sync_ipts = (double)(ist->pts + input_files[ist->file_index].ts_offset - start_time)/ AV_TIME_BASE;
- if (ost->encoding_needed) {
- av_assert0(ist->decoding_needed);
- switch(ost->st->codec->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- do_audio_out(os, ost, ist, decoded_data_buf, decoded_data_size);
- break;
- case AVMEDIA_TYPE_VIDEO:
+ if (ost->encoding_needed) {
+ av_assert0(ist->decoding_needed);
+ switch(ost->st->codec->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ do_audio_out(os, ost, ist, decoded_data_buf, decoded_data_size);
+ break;
+ case AVMEDIA_TYPE_VIDEO:
#if CONFIG_AVFILTER
- if (ost->picref->video && !ost->frame_aspect_ratio)
- ost->st->codec->sample_aspect_ratio = ost->picref->video->sample_aspect_ratio;
+ if (ost->picref->video && !ost->frame_aspect_ratio)
+ ost->st->codec->sample_aspect_ratio = ost->picref->video->sample_aspect_ratio;
#endif
- do_video_out(os, ost, ist, &picture, &frame_size,
- same_quant ? quality : ost->st->codec->global_quality);
- if (vstats_filename && frame_size)
- do_video_stats(os, ost, frame_size);
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- do_subtitle_out(os, ost, ist, &subtitle,
- pkt->pts);
- break;
- default:
- abort();
- }
- } else {
- AVFrame avframe; //FIXME/XXX remove this
- AVPicture pict;
- AVPacket opkt;
- int64_t ost_tb_start_time= av_rescale_q(start_time, AV_TIME_BASE_Q, ost->st->time_base);
-
- av_init_packet(&opkt);
+ do_video_out(os, ost, ist, &picture, &frame_size,
+ same_quant ? quality : ost->st->codec->global_quality);
+ if (vstats_filename && frame_size)
+ do_video_stats(os, ost, frame_size);
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ do_subtitle_out(os, ost, ist, &subtitle,
+ pkt->pts);
+ break;
+ default:
+ abort();
+ }
+ } else {
+ AVFrame avframe; //FIXME/XXX remove this
+ AVPicture pict;
+ AVPacket opkt;
+ int64_t ost_tb_start_time= av_rescale_q(of->start_time, AV_TIME_BASE_Q, ost->st->time_base);
+ av_init_packet(&opkt);
- if ((!ost->frame_number && !(pkt->flags & AV_PKT_FLAG_KEY)) && !copy_initial_nonkeyframes)
+ if ((!ost->frame_number && !(pkt->flags & AV_PKT_FLAG_KEY)) && !copy_initial_nonkeyframes)
#if !CONFIG_AVFILTER
- continue;
+ continue;
#else
- goto cont;
+ goto cont;
#endif
- /* no reencoding needed : output the packet directly */
- /* force the input stream PTS */
+ /* no reencoding needed : output the packet directly */
+ /* force the input stream PTS */
- avcodec_get_frame_defaults(&avframe);
- ost->st->codec->coded_frame= &avframe;
- avframe.key_frame = pkt->flags & AV_PKT_FLAG_KEY;
+ avcodec_get_frame_defaults(&avframe);
+ ost->st->codec->coded_frame= &avframe;
+ avframe.key_frame = pkt->flags & AV_PKT_FLAG_KEY;
- if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
- audio_size += data_size;
- else if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- video_size += data_size;
- ost->sync_opts++;
- }
+ if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ audio_size += data_size;
+ else if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ video_size += data_size;
+ ost->sync_opts++;
+ }
- opkt.stream_index= ost->index;
- if(pkt->pts != AV_NOPTS_VALUE)
- opkt.pts= av_rescale_q(pkt->pts, ist->st->time_base, ost->st->time_base) - ost_tb_start_time;
- else
- opkt.pts= AV_NOPTS_VALUE;
-
- if (pkt->dts == AV_NOPTS_VALUE)
- opkt.dts = av_rescale_q(ist->pts, AV_TIME_BASE_Q, ost->st->time_base);
- else
- opkt.dts = av_rescale_q(pkt->dts, ist->st->time_base, ost->st->time_base);
- opkt.dts -= ost_tb_start_time;
-
- opkt.duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->st->time_base);
- opkt.flags= pkt->flags;
-
- //FIXME remove the following 2 lines they shall be replaced by the bitstream filters
- if( ost->st->codec->codec_id != CODEC_ID_H264
- && ost->st->codec->codec_id != CODEC_ID_MPEG1VIDEO
- && ost->st->codec->codec_id != CODEC_ID_MPEG2VIDEO
- ) {
- if(av_parser_change(ist->st->parser, ost->st->codec, &opkt.data, &opkt.size, data_buf, data_size, pkt->flags & AV_PKT_FLAG_KEY))
- opkt.destruct= av_destruct_packet;
- } else {
- opkt.data = data_buf;
- opkt.size = data_size;
- }
+ opkt.stream_index= ost->index;
+ if(pkt->pts != AV_NOPTS_VALUE)
+ opkt.pts= av_rescale_q(pkt->pts, ist->st->time_base, ost->st->time_base) - ost_tb_start_time;
+ else
+ opkt.pts= AV_NOPTS_VALUE;
+
+ if (pkt->dts == AV_NOPTS_VALUE)
+ opkt.dts = av_rescale_q(ist->pts, AV_TIME_BASE_Q, ost->st->time_base);
+ else
+ opkt.dts = av_rescale_q(pkt->dts, ist->st->time_base, ost->st->time_base);
+ opkt.dts -= ost_tb_start_time;
+
+ opkt.duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->st->time_base);
+ opkt.flags= pkt->flags;
+
+ //FIXME remove the following 2 lines they shall be replaced by the bitstream filters
+ if( ost->st->codec->codec_id != CODEC_ID_H264
+ && ost->st->codec->codec_id != CODEC_ID_MPEG1VIDEO
+ && ost->st->codec->codec_id != CODEC_ID_MPEG2VIDEO
+ ) {
+ if(av_parser_change(ist->st->parser, ost->st->codec, &opkt.data, &opkt.size, data_buf, data_size, pkt->flags & AV_PKT_FLAG_KEY))
+ opkt.destruct= av_destruct_packet;
+ } else {
+ opkt.data = data_buf;
+ opkt.size = data_size;
+ }
- if (os->oformat->flags & AVFMT_RAWPICTURE) {
- /* store AVPicture in AVPacket, as expected by the output format */
- avpicture_fill(&pict, opkt.data, ost->st->codec->pix_fmt, ost->st->codec->width, ost->st->codec->height);
- opkt.data = (uint8_t *)&pict;
- opkt.size = sizeof(AVPicture);
- opkt.flags |= AV_PKT_FLAG_KEY;
- }
- write_frame(os, &opkt, ost->st->codec, ost->bitstream_filters);
- ost->st->codec->frame_number++;
- ost->frame_number++;
- av_free_packet(&opkt);
+ if (os->oformat->flags & AVFMT_RAWPICTURE) {
+ /* store AVPicture in AVPacket, as expected by the output format */
+ avpicture_fill(&pict, opkt.data, ost->st->codec->pix_fmt, ost->st->codec->width, ost->st->codec->height);
+ opkt.data = (uint8_t *)&pict;
+ opkt.size = sizeof(AVPicture);
+ opkt.flags |= AV_PKT_FLAG_KEY;
}
+ write_frame(os, &opkt, ost->st->codec, ost->bitstream_filters);
+ ost->st->codec->frame_number++;
+ ost->frame_number++;
+ av_free_packet(&opkt);
+ }
#if CONFIG_AVFILTER
- cont:
- frame_available = (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) &&
- ost->output_video_filter && avfilter_poll_frame(ost->output_video_filter->inputs[0]);
+ cont:
+ frame_available = (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) &&
+ ost->output_video_filter && avfilter_poll_frame(ost->output_video_filter->inputs[0]);
+ if (ost->picref)
avfilter_unref_buffer(ost->picref);
- }
+ }
#endif
- }
}
av_free(buffer_to_free);
@@ -1772,10 +1795,10 @@ static int output_packet(InputStream *ist, int ist_index,
/* EOF handling */
for(i=0;i<nb_ostreams;i++) {
- ost = ost_table[i];
+ ost = &ost_table[i];
if (ost->source_index == ist_index) {
AVCodecContext *enc= ost->st->codec;
- os = output_files[ost->file_index];
+ os = output_files[ost->file_index].ctx;
if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <=1)
continue;
@@ -1856,105 +1879,66 @@ static int output_packet(InputStream *ist, int ist_index,
return 0;
}
-static void print_sdp(AVFormatContext **avc, int n)
+static void print_sdp(OutputFile *output_files, int n)
{
char sdp[2048];
+ int i;
+ AVFormatContext **avc = av_malloc(sizeof(*avc)*n);
+
+ if (!avc)
+ exit_program(1);
+ for (i = 0; i < n; i++)
+ avc[i] = output_files[i].ctx;
av_sdp_create(avc, n, sdp, sizeof(sdp));
printf("SDP:\n%s\n", sdp);
fflush(stdout);
+ av_freep(&avc);
}
/*
* The following code is the main loop of the file converter
*/
-static int transcode(AVFormatContext **output_files,
+static int transcode(OutputFile *output_files,
int nb_output_files,
InputFile *input_files,
int nb_input_files)
{
- int ret = 0, i, j, k, n, nb_ostreams = 0, step;
-
+ int ret = 0, i, j, step;
AVFormatContext *is, *os;
AVCodecContext *codec, *icodec;
- OutputStream *ost, **ost_table = NULL;
+ OutputStream *ost;
InputStream *ist;
char error[1024];
int key;
int want_sdp = 1;
- uint8_t no_packet[MAX_FILES]={0};
+ uint8_t *no_packet;
int no_packet_count=0;
int nb_frame_threshold[AVMEDIA_TYPE_NB]={0};
int nb_streams[AVMEDIA_TYPE_NB]={0};
+ if (!(no_packet = av_mallocz(nb_input_files)))
+ exit_program(1);
+
if (rate_emu)
for (i = 0; i < nb_input_streams; i++)
input_streams[i].start = av_gettime();
/* output stream init */
- nb_ostreams = 0;
for(i=0;i<nb_output_files;i++) {
- os = output_files[i];
+ os = output_files[i].ctx;
if (!os->nb_streams && !(os->oformat->flags & AVFMT_NOSTREAMS)) {
- av_dump_format(output_files[i], i, output_files[i]->filename, 1);
+ av_dump_format(os, i, os->filename, 1);
fprintf(stderr, "Output file #%d does not contain any stream\n", i);
ret = AVERROR(EINVAL);
goto fail;
}
- nb_ostreams += os->nb_streams;
- }
-
- ost_table = av_mallocz(sizeof(OutputStream *) * nb_ostreams);
- if (!ost_table)
- goto fail;
-
- for(k=0;k<nb_output_files;k++) {
- os = output_files[k];
- for(i=0;i<os->nb_streams;i++,n++) {
- nb_streams[os->streams[i]->codec->codec_type]++;
- }
- }
- for(step=1<<30; step; step>>=1){
- int found_streams[AVMEDIA_TYPE_NB]={0};
- for(j=0; j<AVMEDIA_TYPE_NB; j++)
- nb_frame_threshold[j] += step;
-
- for(j=0; j<nb_input_streams; j++) {
- int skip=0;
- ist = &input_streams[j];
- if(opt_programid){
- int pi,si;
- AVFormatContext *f= input_files[ ist->file_index ].ctx;
- skip=1;
- for(pi=0; pi<f->nb_programs; pi++){
- AVProgram *p= f->programs[pi];
- if(p->id == opt_programid)
- for(si=0; si<p->nb_stream_indexes; si++){
- if(f->streams[ p->stream_index[si] ] == ist->st)
- skip=0;
- }
- }
- }
- if (ist->discard && ist->st->discard != AVDISCARD_ALL && !skip
- && nb_frame_threshold[ist->st->codec->codec_type] <= ist->st->codec_info_nb_frames){
- found_streams[ist->st->codec->codec_type]++;
- }
- }
- for(j=0; j<AVMEDIA_TYPE_NB; j++)
- if(found_streams[j] < nb_streams[j])
- nb_frame_threshold[j] -= step;
- }
- n = 0;
- for(k=0;k<nb_output_files;k++) {
- os = output_files[k];
- for (i = 0; i < os->nb_streams; i++, n++)
- ost_table[n] = output_streams_for_file[k][i];
}
/* for each output stream, we compute the right encoding parameters */
- for(i=0;i<nb_ostreams;i++) {
- ost = ost_table[i];
- os = output_files[ost->file_index];
+ for (i = 0; i < nb_output_streams; i++) {
+ ost = &output_streams[i];
+ os = output_files[ost->file_index].ctx;
ist = &input_streams[ost->source_index];
codec = ost->st->codec;
@@ -2176,8 +2160,8 @@ static int transcode(AVFormatContext **output_files,
}
/* open each encoder */
- for(i=0;i<nb_ostreams;i++) {
- ost = ost_table[i];
+ for (i = 0; i < nb_output_streams; i++) {
+ ost = &output_streams[i];
if (ost->encoding_needed) {
AVCodec *codec = ost->enc;
AVCodecContext *dec = input_streams[ost->source_index].st->codec;
@@ -2224,6 +2208,7 @@ static int transcode(AVFormatContext **output_files,
ret = AVERROR(EINVAL);
goto dump_format;
}
+
if (avcodec_open2(ist->st->codec, codec, &ist->opts) < 0) {
snprintf(error, sizeof(error), "Error while opening decoder for input stream #%d.%d",
ist->file_index, ist->st->index);
@@ -2246,15 +2231,15 @@ static int transcode(AVFormatContext **output_files,
}
/* open files and write file headers */
- for(i=0;i<nb_output_files;i++) {
- os = output_files[i];
- if (avformat_write_header(os, &output_opts[i]) < 0) {
+ for (i = 0; i < nb_output_files; i++) {
+ os = output_files[i].ctx;
+ if (avformat_write_header(os, &output_files[i].opts) < 0) {
snprintf(error, sizeof(error), "Could not write header for output file #%d (incorrect codec parameters ?)", i);
ret = AVERROR(EINVAL);
goto dump_format;
}
-// assert_avoptions(output_opts[i]);
- if (strcmp(output_files[i]->oformat->name, "rtp")) {
+// assert_avoptions(output_files[i].opts);
+ if (strcmp(os->oformat->name, "rtp")) {
want_sdp = 0;
}
}
@@ -2263,14 +2248,14 @@ static int transcode(AVFormatContext **output_files,
/* dump the file output parameters - cannot be done before in case
of stream copy */
for(i=0;i<nb_output_files;i++) {
- av_dump_format(output_files[i], i, output_files[i]->filename, 1);
+ av_dump_format(output_files[i].ctx, i, output_files[i].ctx->filename, 1);
}
/* dump the stream mapping */
if (verbose >= 0) {
fprintf(stderr, "Stream mapping:\n");
- for(i=0;i<nb_ostreams;i++) {
- ost = ost_table[i];
+ for (i = 0; i < nb_output_streams;i ++) {
+ ost = &output_streams[i];
fprintf(stderr, " Stream #%d.%d -> #%d.%d",
input_streams[ost->source_index].file_index,
input_streams[ost->source_index].st->index,
@@ -2307,11 +2292,11 @@ static int transcode(AVFormatContext **output_files,
for(; received_sigterm == 0;) {
int file_index, ist_index;
AVPacket pkt;
- double ipts_min;
+ int64_t ipts_min;
double opts_min;
redo:
- ipts_min= 1e100;
+ ipts_min = INT64_MAX;
opts_min= 1e100;
/* if 'q' pressed, exits */
if (!using_stdin) {
@@ -2345,8 +2330,8 @@ static int transcode(AVFormatContext **output_files,
for(i=0;i<nb_input_streams;i++) {
input_streams[i].st->codec->debug = debug;
}
- for(i=0;i<nb_ostreams;i++) {
- ost = ost_table[i];
+ for(i=0;i<nb_output_streams;i++) {
+ ost = &output_streams[i];
ost->st->codec->debug = debug;
}
if(debug) av_log_set_level(AV_LOG_DEBUG);
@@ -2368,15 +2353,16 @@ static int transcode(AVFormatContext **output_files,
/* select the stream that we must read now by looking at the
smallest output pts */
file_index = -1;
- for(i=0;i<nb_ostreams;i++) {
- double ipts, opts;
- ost = ost_table[i];
- os = output_files[ost->file_index];
+ for (i = 0; i < nb_output_streams; i++) {
+ int64_t ipts;
+ double opts;
+ ost = &output_streams[i];
+ os = output_files[ost->file_index].ctx;
ist = &input_streams[ost->source_index];
- if(ist->is_past_recording_time || no_packet[ist->file_index])
+ if(ost->is_past_recording_time || no_packet[ist->file_index])
continue;
opts = ost->st->pts.val * av_q2d(ost->st->time_base);
- ipts = (double)ist->pts;
+ ipts = ist->pts;
if (!input_files[ist->file_index].eof_reached){
if(ipts < ipts_min) {
ipts_min = ipts;
@@ -2396,7 +2382,7 @@ static int transcode(AVFormatContext **output_files,
if (file_index < 0) {
if(no_packet_count){
no_packet_count=0;
- memset(no_packet, 0, sizeof(no_packet));
+ memset(no_packet, 0, nb_input_files);
usleep(10000);
continue;
}
@@ -2404,7 +2390,7 @@ static int transcode(AVFormatContext **output_files,
}
/* finish if limit size exhausted */
- if (limit_filesize != 0 && limit_filesize <= avio_tell(output_files[0]->pb))
+ if (limit_filesize != 0 && limit_filesize <= avio_tell(output_files[0].ctx->pb))
break;
/* read a frame from it and output it in the fifo */
@@ -2424,7 +2410,7 @@ static int transcode(AVFormatContext **output_files,
}
no_packet_count=0;
- memset(no_packet, 0, sizeof(no_packet));
+ memset(no_packet, 0, nb_input_files);
if (do_pkt_dump) {
av_pkt_dump_log2(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump,
@@ -2467,19 +2453,8 @@ static int transcode(AVFormatContext **output_files,
}
}
- /* finish if recording time exhausted */
- if (recording_time != INT64_MAX &&
- (pkt.pts != AV_NOPTS_VALUE ?
- av_compare_ts(pkt.pts, ist->st->time_base, recording_time + start_time, (AVRational){1, 1000000})
- :
- av_compare_ts(ist->pts, AV_TIME_BASE_Q, recording_time + start_time, (AVRational){1, 1000000})
- )>= 0) {
- ist->is_past_recording_time = 1;
- goto discard_packet;
- }
-
//fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->st->index, pkt.size);
- if (output_packet(ist, ist_index, ost_table, nb_ostreams, &pkt) < 0) {
+ if (output_packet(ist, ist_index, output_streams, nb_output_streams, &pkt) < 0) {
if (verbose >= 0)
fprintf(stderr, "Error while decoding stream #%d.%d\n",
@@ -2494,14 +2469,14 @@ static int transcode(AVFormatContext **output_files,
av_free_packet(&pkt);
/* dump report by using the output first video and audio streams */
- print_report(output_files, ost_table, nb_ostreams, 0);
+ print_report(output_files, output_streams, nb_output_streams, 0);
}
/* at the end of stream, we must flush the decoder buffers */
for (i = 0; i < nb_input_streams; i++) {
ist = &input_streams[i];
if (ist->decoding_needed) {
- output_packet(ist, i, ost_table, nb_ostreams, NULL);
+ output_packet(ist, i, output_streams, nb_output_streams, NULL);
}
}
@@ -2509,16 +2484,16 @@ static int transcode(AVFormatContext **output_files,
/* write the trailer if needed and close file */
for(i=0;i<nb_output_files;i++) {
- os = output_files[i];
+ os = output_files[i].ctx;
av_write_trailer(os);
}
/* dump report by using the first video and audio streams */
- print_report(output_files, ost_table, nb_ostreams, 1);
+ print_report(output_files, output_streams, nb_output_streams, 1);
/* close each encoder */
- for(i=0;i<nb_ostreams;i++) {
- ost = ost_table[i];
+ for (i = 0; i < nb_output_streams; i++) {
+ ost = &output_streams[i];
if (ost->encoding_needed) {
av_freep(&ost->st->codec->stats_in);
avcodec_close(ost->st->codec);
@@ -2541,10 +2516,11 @@ static int transcode(AVFormatContext **output_files,
fail:
av_freep(&bit_buffer);
+ av_freep(&no_packet);
- if (ost_table) {
- for(i=0;i<nb_ostreams;i++) {
- ost = ost_table[i];
+ if (output_streams) {
+ for (i = 0; i < nb_output_streams; i++) {
+ ost = &output_streams[i];
if (ost) {
if (ost->st->stream_copy)
av_freep(&ost->st->codec->extradata);
@@ -2564,10 +2540,8 @@ static int transcode(AVFormatContext **output_files,
if (ost->reformat_ctx)
av_audio_convert_free(ost->reformat_ctx);
av_dict_free(&ost->opts);
- av_free(ost);
}
}
- av_free(ost_table);
}
return ret;
}
@@ -2911,21 +2885,7 @@ static int opt_map_metadata(const char *opt, const char *arg)
static int opt_input_ts_scale(const char *opt, const char *arg)
{
- unsigned int stream;
- double scale;
- char *p;
-
- stream = strtol(arg, &p, 0);
- if (*p)
- p++;
- scale= strtod(p, &p);
-
- if(stream >= MAX_STREAMS)
- exit_program(1);
-
- ts_scale = grow_array(ts_scale, sizeof(*ts_scale), &nb_ts_scale, stream + 1);
- ts_scale[stream] = scale;
- return 0;
+ return av_dict_set(&ts_scale, opt, arg, 0);
}
static int opt_recording_time(const char *opt, const char *arg)
@@ -2998,11 +2958,97 @@ static AVCodec *choose_codec(AVFormatContext *s, AVStream *st, enum AVMediaType
return NULL;
}
+/**
+ * Add all the streams from the given input file to the global
+ * list of input streams.
+ */
+static void add_input_streams(AVFormatContext *ic)
+{
+ int i, rfps, rfps_base, ret;
+
+ for (i = 0; i < ic->nb_streams; i++) {
+ AVStream *st = ic->streams[i];
+ AVCodecContext *dec = st->codec;
+ AVDictionaryEntry *e = NULL;
+ InputStream *ist;
+ char *scale = NULL;
+
+ dec->thread_count = thread_count;
+
+ input_streams = grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, nb_input_streams + 1);
+ ist = &input_streams[nb_input_streams - 1];
+ ist->st = st;
+ ist->file_index = nb_input_files;
+ ist->discard = 1;
+ ist->opts = filter_codec_opts(codec_opts, ist->st->codec->codec_id, ic, st);
+
+ while (e = av_dict_get(ts_scale, "", e, AV_DICT_IGNORE_SUFFIX)) {
+ char *p = strchr(e->key, ':');
+
+ if ((ret = check_stream_specifier(ic, st, p ? p + 1 : "")) > 0)
+ scale = e->value;
+ else if (ret < 0)
+ exit_program(1);
+ }
+ if (scale)
+ ist->ts_scale = strtod(scale, NULL);
+
+ ist->dec = choose_codec(ic, st, dec->codec_type, codec_names);
+
+ switch (dec->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ if(!ist->dec)
+ ist->dec = avcodec_find_decoder(dec->codec_id);
+ if(audio_disable)
+ st->discard= AVDISCARD_ALL;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ if(!ist->dec)
+ ist->dec = avcodec_find_decoder(dec->codec_id);
+ rfps = ic->streams[i]->r_frame_rate.num;
+ rfps_base = ic->streams[i]->r_frame_rate.den;
+ if (dec->lowres) {
+ dec->flags |= CODEC_FLAG_EMU_EDGE;
+ }
+ if(me_threshold)
+ dec->debug |= FF_DEBUG_MV;
+
+ if (dec->time_base.den != rfps*dec->ticks_per_frame || dec->time_base.num != rfps_base) {
+
+ if (verbose >= 0)
+ fprintf(stderr,"\nSeems stream %d codec frame rate differs from container frame rate: %2.2f (%d/%d) -> %2.2f (%d/%d)\n",
+ i, (float)dec->time_base.den / dec->time_base.num, dec->time_base.den, dec->time_base.num,
+
+ (float)rfps / rfps_base, rfps, rfps_base);
+ }
+
+ if(video_disable)
+ st->discard= AVDISCARD_ALL;
+ else if(video_discard)
+ st->discard= video_discard;
+ break;
+ case AVMEDIA_TYPE_DATA:
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ if(!ist->dec)
+ ist->dec = avcodec_find_decoder(dec->codec_id);
+ if(subtitle_disable)
+ st->discard = AVDISCARD_ALL;
+ break;
+ case AVMEDIA_TYPE_ATTACHMENT:
+ case AVMEDIA_TYPE_UNKNOWN:
+ break;
+ default:
+ abort();
+ }
+ }
+}
+
static int opt_input_file(const char *opt, const char *filename)
{
AVFormatContext *ic;
AVInputFormat *file_iformat = NULL;
- int err, i, ret, rfps, rfps_base;
+ int err, i, ret;
int64_t timestamp;
uint8_t buf[128];
AVDictionary **opts;
@@ -3115,72 +3161,7 @@ static int opt_input_file(const char *opt, const char *filename)
}
/* update the current parameters so that they match the one of the input stream */
- for(i=0;i<ic->nb_streams;i++) {
- AVStream *st = ic->streams[i];
- AVCodecContext *dec = st->codec;
- InputStream *ist;
-
- dec->thread_count = thread_count;
-
- input_streams = grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, nb_input_streams + 1);
- ist = &input_streams[nb_input_streams - 1];
- ist->st = st;
- ist->file_index = nb_input_files;
- ist->discard = 1;
- ist->opts = filter_codec_opts(codec_opts, ist->st->codec->codec_id, ic, st);
-
- if (i < nb_ts_scale)
- ist->ts_scale = ts_scale[i];
-
- ist->dec = choose_codec(ic, st, dec->codec_type, codec_names);
-
- switch (dec->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- if(!ist->dec)
- ist->dec = avcodec_find_decoder(dec->codec_id);
- if(audio_disable)
- st->discard= AVDISCARD_ALL;
- break;
- case AVMEDIA_TYPE_VIDEO:
- if(!ist->dec)
- ist->dec = avcodec_find_decoder(dec->codec_id);
- rfps = ic->streams[i]->r_frame_rate.num;
- rfps_base = ic->streams[i]->r_frame_rate.den;
- if (dec->lowres) {
- dec->flags |= CODEC_FLAG_EMU_EDGE;
- }
- if(me_threshold)
- dec->debug |= FF_DEBUG_MV;
-
- if (dec->time_base.den != rfps*dec->ticks_per_frame || dec->time_base.num != rfps_base) {
-
- if (verbose >= 0)
- fprintf(stderr,"\nSeems stream %d codec frame rate differs from container frame rate: %2.2f (%d/%d) -> %2.2f (%d/%d)\n",
- i, (float)dec->time_base.den / dec->time_base.num, dec->time_base.den, dec->time_base.num,
-
- (float)rfps / rfps_base, rfps, rfps_base);
- }
-
- if(video_disable)
- st->discard= AVDISCARD_ALL;
- else if(video_discard)
- st->discard= video_discard;
- break;
- case AVMEDIA_TYPE_DATA:
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- if(!ist->dec)
- ist->dec = avcodec_find_decoder(dec->codec_id);
- if(subtitle_disable)
- st->discard = AVDISCARD_ALL;
- break;
- case AVMEDIA_TYPE_ATTACHMENT:
- case AVMEDIA_TYPE_UNKNOWN:
- break;
- default:
- abort();
- }
- }
+ add_input_streams(ic);
/* dump the file content */
if (verbose >= 0)
@@ -3200,8 +3181,7 @@ static int opt_input_file(const char *opt, const char *filename)
audio_sample_rate = 0;
audio_channels = 0;
audio_sample_fmt = AV_SAMPLE_FMT_NONE;
- av_freep(&ts_scale);
- nb_ts_scale = 0;
+ av_dict_free(&ts_scale);
for (i = 0; i < orig_nb_streams; i++)
av_dict_free(&opts[i]);
@@ -3246,17 +3226,9 @@ static OutputStream *new_output_stream(AVFormatContext *oc, enum AVMediaType typ
exit_program(1);
}
- output_streams_for_file[nb_output_files] =
- grow_array(output_streams_for_file[nb_output_files],
- sizeof(*output_streams_for_file[nb_output_files]),
- &nb_output_streams_for_file[nb_output_files],
- oc->nb_streams);
- ost = output_streams_for_file[nb_output_files][idx] =
- av_mallocz(sizeof(OutputStream));
- if (!ost) {
- fprintf(stderr, "Could not alloc output stream\n");
- exit_program(1);
- }
+ output_streams = grow_array(output_streams, sizeof(*output_streams), &nb_output_streams,
+ nb_output_streams + 1);
+ ost = &output_streams[nb_output_streams - 1];
ost->file_index = nb_output_files;
ost->index = idx;
ost->st = st;
@@ -3516,7 +3488,7 @@ static int opt_streamid(const char *opt, const char *arg)
static int copy_chapters(int infile, int outfile)
{
AVFormatContext *is = input_files[infile].ctx;
- AVFormatContext *os = output_files[outfile];
+ AVFormatContext *os = output_files[outfile].ctx;
int i;
for (i = 0; i < is->nb_chapters; i++) {
@@ -3595,11 +3567,6 @@ static int opt_output_file(const char *opt, const char *filename)
OutputStream *ost;
InputStream *ist;
- if(nb_output_files >= FF_ARRAY_ELEMS(output_files)){
- fprintf(stderr, "Too many output files\n");
- exit_program(1);
- }
-
if (!strcmp(filename, "-"))
filename = "pipe:";
@@ -3697,8 +3664,13 @@ static int opt_output_file(const char *opt, const char *filename)
av_dict_copy(&oc->metadata, metadata, 0);
av_dict_free(&metadata);
- av_dict_copy(&output_opts[nb_output_files], format_opts, 0);
- output_files[nb_output_files++] = oc;
+
+ output_files = grow_array(output_files, sizeof(*output_files), &nb_output_files, nb_output_files + 1);
+ output_files[nb_output_files - 1].ctx = oc;
+ output_files[nb_output_files - 1].ost_index = nb_output_streams - oc->nb_streams;
+ output_files[nb_output_files - 1].recording_time = recording_time;
+ output_files[nb_output_files - 1].start_time = start_time;
+ av_dict_copy(&output_files[nb_output_files - 1].opts, format_opts, 0);
/* check filename in case of an image number is expected */
if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
@@ -3810,9 +3782,9 @@ static int opt_output_file(const char *opt, const char *filename)
av_dict_copy(&oc->metadata, input_files[0].ctx->metadata,
AV_DICT_DONT_OVERWRITE);
if (metadata_streams_autocopy)
- for (i = 0; i < oc->nb_streams; i++) {
- InputStream *ist = &input_streams[output_streams_for_file[nb_output_files-1][i]->source_index];
- av_dict_copy(&oc->streams[i]->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
+ for (i = output_files[nb_output_files - 1].ost_index; i < nb_output_streams; i++) {
+ InputStream *ist = &input_streams[output_streams[i].source_index];
+ av_dict_copy(&output_streams[i].st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
}
frame_rate = (AVRational){0, 0};
@@ -3822,6 +3794,8 @@ static int opt_output_file(const char *opt, const char *filename)
audio_channels = 0;
audio_sample_fmt = AV_SAMPLE_FMT_NONE;
chapters_input_file = INT_MAX;
+ recording_time = INT64_MAX;
+ start_time = 0;
av_freep(&meta_data_maps);
nb_meta_data_maps = 0;
@@ -4203,7 +4177,7 @@ static const OptionDef options[] = {
{ "fs", HAS_ARG | OPT_INT64, {(void*)&limit_filesize}, "set the limit file size in bytes", "limit_size" }, //
{ "ss", HAS_ARG, {(void*)opt_start_time}, "set the start time offset", "time_off" },
{ "itsoffset", HAS_ARG, {(void*)opt_input_ts_offset}, "set the input ts offset", "time_off" },
- { "itsscale", HAS_ARG, {(void*)opt_input_ts_scale}, "set the input ts scale", "stream:scale" },
+ { "itsscale", HAS_ARG, {(void*)opt_input_ts_scale}, "set the input ts scale", "scale" },
{ "metadata", HAS_ARG, {(void*)opt_metadata}, "add metadata", "string=string" },
{ "dframes", OPT_INT | HAS_ARG, {(void*)&max_frames[AVMEDIA_TYPE_DATA]}, "set the number of data frames to record", "number" },
{ "benchmark", OPT_BOOL | OPT_EXPERT, {(void*)&do_benchmark},
diff --git a/doc/general.texi b/doc/general.texi
index c5045b1095..1708e1b29f 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -260,6 +260,8 @@ library:
@tab Multimedia format used in Westwood Studios games.
@item Westwood Studios VQA @tab @tab X
@tab Multimedia format used in Westwood Studios games.
+@item XMV @tab @tab X
+ @tab Microsoft video container used in Xbox games.
@item xWMA @tab @tab X
@tab Microsoft audio container used by XAudio 2.
@item YUV4MPEG pipe @tab X @tab X
diff --git a/ffmpeg.c b/ffmpeg.c
index e895b787aa..8e2c29fe14 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -736,7 +736,6 @@ static int read_ffserver_streams(AVFormatContext *s, const char *filename)
{
int i, err;
AVFormatContext *ic = NULL;
- int nopts = 0;
err = avformat_open_input(&ic, filename, NULL, NULL);
if (err < 0)
@@ -768,9 +767,6 @@ static int read_ffserver_streams(AVFormatContext *s, const char *filename)
} else
choose_pixel_fmt(st, codec);
}
-
- if(st->codec->flags & CODEC_FLAG_BITEXACT)
- nopts = 1;
}
av_close_input_file(ic);
@@ -1725,6 +1721,14 @@ static int output_packet(InputStream *ist, int ist_index,
int frame_size;
ost = ost_table[i];
+
+ /* finish if recording time exhausted */
+ if (recording_time != INT64_MAX &&
+ av_compare_ts(ist->pts, AV_TIME_BASE_Q, recording_time + start_time, (AVRational){1, 1000000})
+ >= 0) {
+ ist->is_past_recording_time = 1;
+ continue;
+ }
if (ost->source_index == ist_index) {
#if CONFIG_AVFILTER
frame_available = ist->st->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
@@ -2804,17 +2808,6 @@ static int transcode(AVFormatContext **output_files,
}
}
- /* finish if recording time exhausted */
- if (recording_time != INT64_MAX &&
- (pkt.pts != AV_NOPTS_VALUE ?
- av_compare_ts(pkt.pts, ist->st->time_base, recording_time + start_time, (AVRational){1, 1000000})
- :
- av_compare_ts(ist->pts, AV_TIME_BASE_Q, recording_time + start_time, (AVRational){1, 1000000})
- )>= 0) {
- ist->is_past_recording_time = 1;
- goto discard_packet;
- }
-
//fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->st->index, pkt.size);
if (output_packet(ist, ist_index, ost_table, nb_ostreams, &pkt) < 0) {
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index e0e19a21a1..147c1b3587 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -635,6 +635,8 @@ OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \
mpeg12.o mpeg12data.o \
mpegvideo.o error_resilience.o
OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o
+OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o
+OBJS-$(CONFIG_RV40_PARSER) += rv34_parser.o
OBJS-$(CONFIG_VC1_PARSER) += vc1_parser.o vc1.o vc1data.o \
msmpeg4.o msmpeg4data.o mpeg4video.o \
h263.o mpegvideo.o error_resilience.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 89955017e0..8ca6181e45 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -409,6 +409,8 @@ void avcodec_register_all(void)
REGISTER_PARSER (MPEGAUDIO, mpegaudio);
REGISTER_PARSER (MPEGVIDEO, mpegvideo);
REGISTER_PARSER (PNM, pnm);
+ REGISTER_PARSER (RV30, rv30);
+ REGISTER_PARSER (RV40, rv40);
REGISTER_PARSER (VC1, vc1);
REGISTER_PARSER (VP3, vp3);
REGISTER_PARSER (VP8, vp8);
diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c
index 3a59d5f477..0f91020a2d 100644
--- a/libavcodec/h264_refs.c
+++ b/libavcodec/h264_refs.c
@@ -655,7 +655,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
print_short_term(h);
print_long_term(h);
- return err;
+ return h->s.avctx->error_recognition >= FF_ER_EXPLODE ? err : 0;
}
int ff_h264_decode_ref_pic_marking(H264Context *h, GetBitContext *gb){
diff --git a/libavcodec/rv34_parser.c b/libavcodec/rv34_parser.c
new file mode 100644
index 0000000000..ce8604345e
--- /dev/null
+++ b/libavcodec/rv34_parser.c
@@ -0,0 +1,95 @@
+/*
+ * RV30/40 parser
+ * Copyright (c) 2011 Konstantin Shishkov
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * RV30/40 parser
+ */
+
+#include "parser.h"
+#include "libavutil/intreadwrite.h"
+
+typedef struct {
+ ParseContext pc;
+ int64_t key_dts;
+ int key_pts;
+} RV34ParseContext;
+
+static const int rv_to_av_frame_type[4] = {
+ AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B,
+};
+
+static int rv34_parse(AVCodecParserContext *s,
+ AVCodecContext *avctx,
+ const uint8_t **poutbuf, int *poutbuf_size,
+ const uint8_t *buf, int buf_size)
+{
+ RV34ParseContext *pc = s->priv_data;
+ int type, pts, hdr;
+
+ if (buf_size < 13 + *buf * 8) {
+ *poutbuf = buf;
+ *poutbuf_size = buf_size;
+ return buf_size;
+ }
+
+ hdr = AV_RB32(buf + 9 + *buf * 8);
+ if (avctx->codec_id == CODEC_ID_RV30) {
+ type = (hdr >> 27) & 3;
+ pts = (hdr >> 7) & 0x1FFF;
+ } else {
+ type = (hdr >> 29) & 3;
+ pts = (hdr >> 6) & 0x1FFF;
+ }
+
+ if (type != 3 && s->pts != AV_NOPTS_VALUE) {
+ pc->key_dts = s->pts;
+ pc->key_pts = pts;
+ } else {
+ if (type != 3)
+ s->pts = pc->key_dts + ((pts - pc->key_pts) & 0x1FFF);
+ else
+ s->pts = pc->key_dts - ((pc->key_pts - pts) & 0x1FFF);
+ }
+ s->pict_type = rv_to_av_frame_type[type];
+
+ *poutbuf = buf;
+ *poutbuf_size = buf_size;
+ return buf_size;
+}
+
+#ifdef CONFIG_RV30_PARSER
+AVCodecParser ff_rv30_parser = {
+ { CODEC_ID_RV30 },
+ sizeof(RV34ParseContext),
+ NULL,
+ rv34_parse,
+};
+#endif
+
+#ifdef CONFIG_RV40_PARSER
+AVCodecParser ff_rv40_parser = {
+ { CODEC_ID_RV40 },
+ sizeof(RV34ParseContext),
+ NULL,
+ rv34_parse,
+};
+#endif
diff --git a/libavcodec/x86/dsputil_yasm.asm b/libavcodec/x86/dsputil_yasm.asm
index 1f5a4f68c7..794b549a79 100644
--- a/libavcodec/x86/dsputil_yasm.asm
+++ b/libavcodec/x86/dsputil_yasm.asm
@@ -20,6 +20,7 @@
;******************************************************************************
%include "x86inc.asm"
+%include "x86util.asm"
SECTION_RODATA
pb_f: times 16 db 15
@@ -1054,39 +1055,6 @@ emu_edge mmx
; int32_t max, unsigned int len)
;-----------------------------------------------------------------------------
-%macro PMINSD_MMX 3 ; dst, src, tmp
- mova %3, %2
- pcmpgtd %3, %1
- pxor %1, %2
- pand %1, %3
- pxor %1, %2
-%endmacro
-
-%macro PMAXSD_MMX 3 ; dst, src, tmp
- mova %3, %1
- pcmpgtd %3, %2
- pand %1, %3
- pandn %3, %2
- por %1, %3
-%endmacro
-
-%macro CLIPD_MMX 3-4 ; src/dst, min, max, tmp
- PMINSD_MMX %1, %3, %4
- PMAXSD_MMX %1, %2, %4
-%endmacro
-
-%macro CLIPD_SSE2 3-4 ; src/dst, min (float), max (float), unused
- cvtdq2ps %1, %1
- minps %1, %3
- maxps %1, %2
- cvtps2dq %1, %1
-%endmacro
-
-%macro CLIPD_SSE41 3-4 ; src/dst, min, max, unused
- pminsd %1, %3
- pmaxsd %1, %2
-%endmacro
-
%macro SPLATD_MMX 1
punpckldq %1, %1
%endmacro
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 9f5bfb42ad..d597c624a9 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -305,6 +305,7 @@ OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv.o asfdec.o asf.o asfcry
avlanguage.o mpegts.o isom.o riff.o
OBJS-$(CONFIG_WV_DEMUXER) += wv.o apetag.o
OBJS-$(CONFIG_XA_DEMUXER) += xa.o
+OBJS-$(CONFIG_XMV_DEMUXER) += xmv.o
OBJS-$(CONFIG_XWMA_DEMUXER) += xwma.o riff.o
OBJS-$(CONFIG_YOP_DEMUXER) += yop.o
OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index a9fa117243..c64c355523 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -227,6 +227,7 @@ void av_register_all(void)
REGISTER_DEMUXER (WTV, wtv);
REGISTER_DEMUXER (WV, wv);
REGISTER_DEMUXER (XA, xa);
+ REGISTER_DEMUXER (XMV, xmv);
REGISTER_DEMUXER (XWMA, xwma);
REGISTER_DEMUXER (YOP, yop);
REGISTER_MUXDEMUX (YUV4MPEGPIPE, yuv4mpegpipe);
diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c
index 461c45c81c..7f25af7994 100644
--- a/libavformat/rmdec.c
+++ b/libavformat/rmdec.c
@@ -293,20 +293,21 @@ ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVIOContext *pb,
// av_log(s, AV_LOG_DEBUG, "%X %X\n", st->codec->codec_tag, MKTAG('R', 'V', '2', '0'));
if (st->codec->codec_id == CODEC_ID_NONE)
goto fail1;
- st->codec->width = avio_rb16(pb);
+ st->codec->width = avio_rb16(pb);
st->codec->height = avio_rb16(pb);
- st->codec->time_base.num= 1;
- fps= avio_rb16(pb);
+ avio_skip(pb, 2); // looks like bits per sample
+ avio_skip(pb, 4); // always zero?
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- avio_rb32(pb);
- avio_skip(pb, 2);
- avio_rb16(pb);
+ st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS;
+ fps = avio_rb32(pb);
if ((ret = rm_read_extradata(pb, st->codec, codec_data_size - (avio_tell(pb) - codec_pos))) < 0)
return ret;
-// av_log(s, AV_LOG_DEBUG, "fps= %d fps2= %d\n", fps, fps2);
- st->codec->time_base.den = fps * st->codec->time_base.num;
+ av_reduce(&st->codec->time_base.num, &st->codec->time_base.den,
+ 0x10000, fps, (1 << 30) - 1);
+ st->avg_frame_rate.num = st->codec->time_base.den;
+ st->avg_frame_rate.den = st->codec->time_base.num;
}
skip:
@@ -570,7 +571,8 @@ skip:
static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb,
RMDemuxContext *rm, RMStream *vst,
- AVPacket *pkt, int len, int *pseq)
+ AVPacket *pkt, int len, int *pseq,
+ int64_t *timestamp)
{
int hdr, seq, pic_num, len2, pos;
int type;
@@ -590,8 +592,10 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb,
return -1;
rm->remaining_len = len;
if(type&1){ // frame, not slice
- if(type == 3) // frame as a part of packet
+ if(type == 3){ // frame as a part of packet
len= len2;
+ *timestamp = pos;
+ }
if(rm->remaining_len < len)
return -1;
rm->remaining_len -= len;
@@ -699,7 +703,7 @@ ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb,
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
rm->current_stream= st->id;
- if(rm_assemble_video_frame(s, pb, rm, ast, pkt, len, seq))
+ if(rm_assemble_video_frame(s, pb, rm, ast, pkt, len, seq, &timestamp))
return -1; //got partial frame
} else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
if ((st->codec->codec_id == CODEC_ID_RA_288) ||
@@ -774,7 +778,7 @@ ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb,
}
#endif
- pkt->pts= timestamp;
+ pkt->pts = timestamp;
if (flags & 2)
pkt->flags |= AV_PKT_FLAG_KEY;
diff --git a/libavformat/version.h b/libavformat/version.h
index 5b6031b3ec..f811c31e9b 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -24,7 +24,7 @@
#include "libavutil/avutil.h"
#define LIBAVFORMAT_VERSION_MAJOR 53
-#define LIBAVFORMAT_VERSION_MINOR 7
+#define LIBAVFORMAT_VERSION_MINOR 8
#define LIBAVFORMAT_VERSION_MICRO 0
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
diff --git a/libavformat/xmv.c b/libavformat/xmv.c
new file mode 100644
index 0000000000..a6081aff7b
--- /dev/null
+++ b/libavformat/xmv.c
@@ -0,0 +1,576 @@
+/*
+ * Microsoft XMV demuxer
+ * Copyright (c) 2011 Sven Hesse <drmccoy@drmccoy.de>
+ * Copyright (c) 2011 Matthew Hoops <clone2727@gmail.com>
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Microsoft XMV demuxer
+ */
+
+#include <stdint.h>
+
+#include "libavutil/intreadwrite.h"
+
+#include "avformat.h"
+#include "riff.h"
+
+#define XMV_MIN_HEADER_SIZE 36
+
+#define XMV_AUDIO_ADPCM51_FRONTLEFTRIGHT 1
+#define XMV_AUDIO_ADPCM51_FRONTCENTERLOW 2
+#define XMV_AUDIO_ADPCM51_REARLEFTRIGHT 4
+
+#define XMV_AUDIO_ADPCM51 (XMV_AUDIO_ADPCM51_FRONTLEFTRIGHT | \
+ XMV_AUDIO_ADPCM51_FRONTCENTERLOW | \
+ XMV_AUDIO_ADPCM51_REARLEFTRIGHT)
+
+typedef struct XMVAudioTrack {
+ uint16_t compression;
+ uint16_t channels;
+ uint32_t sample_rate;
+ uint16_t bits_per_sample;
+ uint32_t bit_rate;
+ uint16_t flags;
+ uint16_t block_align;
+ uint16_t block_samples;
+
+ enum CodecID codec_id;
+} XMVAudioTrack;
+
+typedef struct XMVVideoPacket {
+ /* The decoder stream index for this video packet. */
+ int stream_index;
+
+ uint32_t data_size;
+ uint32_t data_offset;
+
+ uint32_t current_frame;
+ uint32_t frame_count;
+
+ /* Does the video packet contain extra data? */
+ int has_extradata;
+
+ /* Extra data */
+ uint8_t extradata[4];
+
+ int64_t last_pts;
+ int64_t pts;
+} XMVVideoPacket;
+
+typedef struct XMVAudioPacket {
+ /* The decoder stream index for this audio packet. */
+ int stream_index;
+
+ /* The audio track this packet encodes. */
+ XMVAudioTrack *track;
+
+ uint32_t data_size;
+ uint32_t data_offset;
+
+ uint32_t frame_size;
+
+ uint32_t block_count;
+} XMVAudioPacket;
+
+typedef struct XMVDemuxContext {
+ uint16_t audio_track_count;
+
+ XMVAudioTrack *audio_tracks;
+
+ uint32_t this_packet_size;
+ uint32_t next_packet_size;
+
+ uint32_t this_packet_offset;
+ uint32_t next_packet_offset;
+
+ uint16_t current_stream;
+ uint16_t stream_count;
+
+ XMVVideoPacket video;
+ XMVAudioPacket *audio;
+} XMVDemuxContext;
+
+static int xmv_probe(AVProbeData *p)
+{
+ uint32_t file_version;
+
+ if (p->buf_size < XMV_MIN_HEADER_SIZE)
+ return 0;
+
+ file_version = AV_RL32(p->buf + 16);
+ if ((file_version == 0) || (file_version > 4))
+ return 0;
+
+ if (!memcmp(p->buf + 12, "xobX", 4))
+ return AVPROBE_SCORE_MAX;
+
+ return 0;
+}
+
+static int xmv_read_header(AVFormatContext *s,
+ AVFormatParameters *ap)
+{
+ XMVDemuxContext *xmv = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *vst = NULL;
+
+ uint32_t file_version;
+ uint32_t this_packet_size;
+ uint16_t audio_track;
+
+ avio_skip(pb, 4); /* Next packet size */
+
+ this_packet_size = avio_rl32(pb);
+
+ avio_skip(pb, 4); /* Max packet size */
+ avio_skip(pb, 4); /* "xobX" */
+
+ file_version = avio_rl32(pb);
+ if ((file_version != 4) && (file_version != 2))
+ av_log_ask_for_sample(s, "Found uncommon version %d\n", file_version);
+
+
+ /* Video track */
+
+ vst = av_new_stream(s, 0);
+ if (!vst)
+ return AVERROR(ENOMEM);
+
+ av_set_pts_info(vst, 32, 1, 1000);
+
+ vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ vst->codec->codec_id = CODEC_ID_WMV2;
+ vst->codec->codec_tag = MKBETAG('W', 'M', 'V', '2');
+ vst->codec->width = avio_rl32(pb);
+ vst->codec->height = avio_rl32(pb);
+
+ vst->duration = avio_rl32(pb);
+
+ xmv->video.stream_index = vst->index;
+
+ /* Audio tracks */
+
+ xmv->audio_track_count = avio_rl16(pb);
+
+ avio_skip(pb, 2); /* Unknown (padding?) */
+
+ xmv->audio_tracks = av_malloc(xmv->audio_track_count * sizeof(XMVAudioTrack));
+ if (!xmv->audio_tracks)
+ return AVERROR(ENOMEM);
+
+ xmv->audio = av_malloc(xmv->audio_track_count * sizeof(XMVAudioPacket));
+ if (!xmv->audio)
+ return AVERROR(ENOMEM);
+
+ for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) {
+ XMVAudioTrack *track = &xmv->audio_tracks[audio_track];
+ XMVAudioPacket *packet = &xmv->audio [audio_track];
+ AVStream *ast = NULL;
+
+ track->compression = avio_rl16(pb);
+ track->channels = avio_rl16(pb);
+ track->sample_rate = avio_rl32(pb);
+ track->bits_per_sample = avio_rl16(pb);
+ track->flags = avio_rl16(pb);
+
+ track->bit_rate = track->bits_per_sample *
+ track->sample_rate *
+ track->channels;
+ track->block_align = 36 * track->channels;
+ track->block_samples = 64;
+ track->codec_id = ff_wav_codec_get_id(track->compression,
+ track->bits_per_sample);
+
+ packet->track = track;
+ packet->stream_index = -1;
+
+ packet->frame_size = 0;
+ packet->block_count = 0;
+
+ /* TODO: ADPCM'd 5.1 sound is encoded in three separate streams.
+ * Those need to be interleaved to a proper 5.1 stream. */
+ if (track->flags & XMV_AUDIO_ADPCM51)
+ av_log(s, AV_LOG_WARNING, "Unsupported 5.1 ADPCM audio stream "
+ "(0x%04X)\n", track->flags);
+
+ ast = av_new_stream(s, audio_track);
+ if (!ast)
+ return AVERROR(ENOMEM);
+
+ ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ ast->codec->codec_id = track->codec_id;
+ ast->codec->codec_tag = track->compression;
+ ast->codec->channels = track->channels;
+ ast->codec->sample_rate = track->sample_rate;
+ ast->codec->bits_per_coded_sample = track->bits_per_sample;
+ ast->codec->bit_rate = track->bit_rate;
+ ast->codec->block_align = 36 * track->channels;
+
+ av_set_pts_info(ast, 32, track->block_samples, track->sample_rate);
+
+ packet->stream_index = ast->index;
+
+ ast->duration = vst->duration;
+ }
+
+
+ /** Initialize the packet context */
+
+ xmv->next_packet_offset = avio_tell(pb);
+
+ xmv->next_packet_size = this_packet_size - xmv->next_packet_offset;
+ xmv->this_packet_size = 0;
+
+ xmv->video.current_frame = 0;
+ xmv->video.frame_count = 0;
+ xmv->video.pts = 0;
+ xmv->video.last_pts = 0;
+
+ xmv->current_stream = 0;
+ xmv->stream_count = xmv->audio_track_count + 1;
+
+ return 0;
+}
+
+static void xmv_read_extradata(uint8_t *extradata, AVIOContext *pb)
+{
+ /* Read the XMV extradata */
+
+ uint32_t data = avio_rl32(pb);
+
+ int mspel_bit = !!(data & 0x01);
+ int loop_filter = !!(data & 0x02);
+ int abt_flag = !!(data & 0x04);
+ int j_type_bit = !!(data & 0x08);
+ int top_left_mv_flag = !!(data & 0x10);
+ int per_mb_rl_bit = !!(data & 0x20);
+ int slice_count = (data >> 6) & 7;
+
+ /* Write it back as standard WMV2 extradata */
+
+ data = 0;
+
+ data |= mspel_bit << 15;
+ data |= loop_filter << 14;
+ data |= abt_flag << 13;
+ data |= j_type_bit << 12;
+ data |= top_left_mv_flag << 11;
+ data |= per_mb_rl_bit << 10;
+ data |= slice_count << 7;
+
+ AV_WB32(extradata, data);
+}
+
+static int xmv_process_packet_header(AVFormatContext *s)
+{
+ XMVDemuxContext *xmv = s->priv_data;
+ AVIOContext *pb = s->pb;
+
+ uint8_t data[8];
+ uint16_t audio_track;
+ uint32_t data_offset;
+
+ /* Next packet size */
+ xmv->next_packet_size = avio_rl32(pb);
+
+ /* Packet video header */
+
+ if (avio_read(pb, data, 8) != 8)
+ return AVERROR(EIO);
+
+ xmv->video.data_size = AV_RL32(data) & 0x007FFFFF;
+
+ xmv->video.current_frame = 0;
+ xmv->video.frame_count = (AV_RL32(data) >> 23) & 0xFF;
+
+ xmv->video.has_extradata = (data[3] & 0x80) != 0;
+
+ /* Adding the audio data sizes and the video data size keeps you 4 bytes
+ * short for every audio track. But as playing around with XMV files with
+ * ADPCM audio showed, taking the extra 4 bytes from the audio data gives
+ * you either completely distorted audio or click (when skipping the
+ * remaining 68 bytes of the ADPCM block). Substracting 4 bytes for every
+ * audio track from the video data works at least for the audio. Probably
+ * some alignment thing?
+ * The video data has (always?) lots of padding, so it should work out...
+ */
+ xmv->video.data_size -= xmv->audio_track_count * 4;
+
+ xmv->current_stream = 0;
+ if (!xmv->video.frame_count) {
+ xmv->video.frame_count = 1;
+ xmv->current_stream = 1;
+ }
+
+ /* Packet audio header */
+
+ for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) {
+ XMVAudioPacket *packet = &xmv->audio[audio_track];
+
+ if (avio_read(pb, data, 4) != 4)
+ return AVERROR(EIO);
+
+ packet->data_size = AV_RL32(data) & 0x007FFFFF;
+ if ((packet->data_size == 0) && (audio_track != 0))
+ /* This happens when I create an XMV with several identical audio
+ * streams. From the size calculations, duplicating the previous
+ * stream's size works out, but the track data itself is silent.
+ * Maybe this should also redirect the offset to the previous track?
+ */
+ packet->data_size = xmv->audio[audio_track - 1].data_size;
+
+ /** Carve up the audio data in frame_count slices */
+ packet->frame_size = packet->data_size / xmv->video.frame_count;
+ packet->frame_size -= packet->frame_size % packet->track->block_align;
+ }
+
+ /* Packet data offsets */
+
+ data_offset = avio_tell(pb);
+
+ xmv->video.data_offset = data_offset;
+ data_offset += xmv->video.data_size;
+
+ for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) {
+ xmv->audio[audio_track].data_offset = data_offset;
+ data_offset += xmv->audio[audio_track].data_size;
+ }
+
+ /* Video frames header */
+
+ /* Read new video extra data */
+ if (xmv->video.data_size > 0) {
+ if (xmv->video.has_extradata) {
+ xmv_read_extradata(xmv->video.extradata, pb);
+
+ xmv->video.data_size -= 4;
+ xmv->video.data_offset += 4;
+
+ if (xmv->video.stream_index >= 0) {
+ AVStream *vst = s->streams[xmv->video.stream_index];
+
+ assert(xmv->video.stream_index < s->nb_streams);
+
+ if (vst->codec->extradata_size < 4) {
+ av_free(vst->codec->extradata);
+
+ vst->codec->extradata =
+ av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE);
+ vst->codec->extradata_size = 4;
+ }
+
+ memcpy(vst->codec->extradata, xmv->video.extradata, 4);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int xmv_fetch_new_packet(AVFormatContext *s)
+{
+ XMVDemuxContext *xmv = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int result;
+
+ /* Seek to it */
+ xmv->this_packet_offset = xmv->next_packet_offset;
+ if (avio_seek(pb, xmv->this_packet_offset, SEEK_SET) != xmv->this_packet_offset)
+ return AVERROR(EIO);
+
+ /* Update the size */
+ xmv->this_packet_size = xmv->next_packet_size;
+ if (xmv->this_packet_size < (12 + xmv->audio_track_count * 4))
+ return AVERROR(EIO);
+
+ /* Process the header */
+ result = xmv_process_packet_header(s);
+ if (result)
+ return result;
+
+ /* Update the offset */
+ xmv->next_packet_offset = xmv->this_packet_offset + xmv->this_packet_size;
+
+ return 0;
+}
+
+static int xmv_fetch_audio_packet(AVFormatContext *s,
+ AVPacket *pkt, uint32_t stream)
+{
+ XMVDemuxContext *xmv = s->priv_data;
+ AVIOContext *pb = s->pb;
+ XMVAudioPacket *audio = &xmv->audio[stream];
+
+ uint32_t data_size;
+ uint32_t block_count;
+ int result;
+
+ /* Seek to it */
+ if (avio_seek(pb, audio->data_offset, SEEK_SET) != audio->data_offset)
+ return AVERROR(EIO);
+
+ if ((xmv->video.current_frame + 1) < xmv->video.frame_count)
+ /* Not the last frame, get at most frame_size bytes. */
+ data_size = FFMIN(audio->frame_size, audio->data_size);
+ else
+ /* Last frame, get the rest. */
+ data_size = audio->data_size;
+
+ /* Read the packet */
+ result = av_get_packet(pb, pkt, data_size);
+ if (result <= 0)
+ return result;
+
+ pkt->stream_index = audio->stream_index;
+
+ /* Calculate the PTS */
+
+ block_count = data_size / audio->track->block_align;
+
+ pkt->duration = block_count;
+ pkt->pts = audio->block_count;
+ pkt->dts = AV_NOPTS_VALUE;
+
+ audio->block_count += block_count;
+
+ /* Advance offset */
+ audio->data_size -= data_size;
+ audio->data_offset += data_size;
+
+ return 0;
+}
+
+static int xmv_fetch_video_packet(AVFormatContext *s,
+ AVPacket *pkt)
+{
+ XMVDemuxContext *xmv = s->priv_data;
+ AVIOContext *pb = s->pb;
+ XMVVideoPacket *video = &xmv->video;
+
+ int result;
+ uint32_t frame_header;
+ uint32_t frame_size, frame_timestamp;
+ uint32_t i;
+
+ /* Seek to it */
+ if (avio_seek(pb, video->data_offset, SEEK_SET) != video->data_offset)
+ return AVERROR(EIO);
+
+ /* Read the frame header */
+ frame_header = avio_rl32(pb);
+
+ frame_size = (frame_header & 0x1FFFF) * 4 + 4;
+ frame_timestamp = (frame_header >> 17);
+
+ if ((frame_size + 4) > video->data_size)
+ return AVERROR(EIO);
+
+ /* Create the packet */
+ result = av_new_packet(pkt, frame_size);
+ if (result)
+ return result;
+
+ /* Contrary to normal WMV2 video, the bit stream in XMV's
+ * WMV2 is little-endian.
+ * TODO: This manual swap is of course suboptimal.
+ */
+ for (i = 0; i < frame_size; i += 4)
+ AV_WB32(pkt->data + i, avio_rl32(pb));
+
+ pkt->stream_index = video->stream_index;
+
+ /* Calculate the PTS */
+
+ video->last_pts = frame_timestamp + video->pts;
+
+ pkt->duration = 0;
+ pkt->pts = video->last_pts;
+ pkt->dts = AV_NOPTS_VALUE;
+
+ video->pts += frame_timestamp;
+
+ /* Keyframe? */
+ pkt->flags = (pkt->data[0] & 0x80) ? 0 : AV_PKT_FLAG_KEY;
+
+ /* Advance offset */
+ video->data_size -= frame_size + 4;
+ video->data_offset += frame_size + 4;
+
+ return 0;
+}
+
+static int xmv_read_packet(AVFormatContext *s,
+ AVPacket *pkt)
+{
+ XMVDemuxContext *xmv = s->priv_data;
+ int result;
+
+ if (xmv->video.current_frame == xmv->video.frame_count) {
+ /* No frames left in this packet, so we fetch a new one */
+
+ result = xmv_fetch_new_packet(s);
+ if (result)
+ return result;
+ }
+
+ if (xmv->current_stream == 0) {
+ /* Fetch a video frame */
+
+ result = xmv_fetch_video_packet(s, pkt);
+ if (result)
+ return result;
+
+ } else {
+ /* Fetch an audio frame */
+
+ result = xmv_fetch_audio_packet(s, pkt, xmv->current_stream - 1);
+ if (result)
+ return result;
+ }
+
+ /* Increase our counters */
+ if (++xmv->current_stream >= xmv->stream_count) {
+ xmv->current_stream = 0;
+ xmv->video.current_frame += 1;
+ }
+
+ return 0;
+}
+
+static int xmv_read_close(AVFormatContext *s)
+{
+ XMVDemuxContext *xmv = s->priv_data;
+
+ av_free(xmv->audio);
+ av_free(xmv->audio_tracks);
+
+ return 0;
+}
+
+AVInputFormat ff_xmv_demuxer = {
+ .name = "xmv",
+ .long_name = NULL_IF_CONFIG_SMALL("Microsoft XMV"),
+ .priv_data_size = sizeof(XMVDemuxContext),
+ .read_probe = xmv_probe,
+ .read_header = xmv_read_header,
+ .read_packet = xmv_read_packet,
+ .read_close = xmv_read_close,
+};
diff --git a/libavutil/x86/x86util.asm b/libavutil/x86/x86util.asm
index 1cede4d336..fc4781b532 100644
--- a/libavutil/x86/x86util.asm
+++ b/libavutil/x86/x86util.asm
@@ -540,3 +540,36 @@
pmaxsw %1, %2
pminsw %1, %3
%endmacro
+
+%macro PMINSD_MMX 3 ; dst, src, tmp
+ mova %3, %2
+ pcmpgtd %3, %1
+ pxor %1, %2
+ pand %1, %3
+ pxor %1, %2
+%endmacro
+
+%macro PMAXSD_MMX 3 ; dst, src, tmp
+ mova %3, %1
+ pcmpgtd %3, %2
+ pand %1, %3
+ pandn %3, %2
+ por %1, %3
+%endmacro
+
+%macro CLIPD_MMX 3-4 ; src/dst, min, max, tmp
+ PMINSD_MMX %1, %3, %4
+ PMAXSD_MMX %1, %2, %4
+%endmacro
+
+%macro CLIPD_SSE2 3-4 ; src/dst, min (float), max (float), unused
+ cvtdq2ps %1, %1
+ minps %1, %3
+ maxps %1, %2
+ cvtps2dq %1, %1
+%endmacro
+
+%macro CLIPD_SSE41 3-4 ; src/dst, min, max, unused
+ pminsd %1, %3
+ pmaxsd %1, %2
+%endmacro
diff --git a/libswscale/ppc/swscale_altivec.c b/libswscale/ppc/swscale_altivec.c
index 8a5bac308e..439aa91461 100644
--- a/libswscale/ppc/swscale_altivec.c
+++ b/libswscale/ppc/swscale_altivec.c
@@ -400,7 +400,7 @@ void ff_sws_init_swScale_altivec(SwsContext *c)
return;
if (c->srcBpc == 8 && c->dstBpc <= 10) {
- c->hScale = hScale_altivec_real;
+ c->hyScale = c->hcScale = hScale_altivec_real;
}
if (!is16BPS(dstFormat) && !is9_OR_10BPS(dstFormat) &&
dstFormat != PIX_FMT_NV12 && dstFormat != PIX_FMT_NV21 &&
diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index e94a6f7a7c..0f886486e8 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -2212,7 +2212,7 @@ static av_always_inline void hyscale(SwsContext *c, int16_t *dst, int dstWidth,
int shift= isAnyRGB(c->srcFormat) || c->srcFormat==PIX_FMT_PAL8 ? 13 : av_pix_fmt_descriptors[c->srcFormat].comp[0].depth_minus1;
c->hScale16(dst, dstWidth, (const uint16_t*)src, srcW, xInc, hLumFilter, hLumFilterPos, hLumFilterSize, shift);
} else if (!c->hyscale_fast) {
- c->hScale(c, dst, dstWidth, src, hLumFilter, hLumFilterPos, hLumFilterSize);
+ c->hyScale(c, dst, dstWidth, src, hLumFilter, hLumFilterPos, hLumFilterSize);
} else { // fast bilinear upscale / crap downscale
c->hyscale_fast(c, dst, dstWidth, src, srcW, xInc);
}
@@ -2258,8 +2258,8 @@ static av_always_inline void hcscale(SwsContext *c, int16_t *dst1, int16_t *dst2
c->hScale16(dst1, dstWidth, (const uint16_t*)src1, srcW, xInc, hChrFilter, hChrFilterPos, hChrFilterSize, shift);
c->hScale16(dst2, dstWidth, (const uint16_t*)src2, srcW, xInc, hChrFilter, hChrFilterPos, hChrFilterSize, shift);
} else if (!c->hcscale_fast) {
- c->hScale(c, dst1, dstWidth, src1, hChrFilter, hChrFilterPos, hChrFilterSize);
- c->hScale(c, dst2, dstWidth, src2, hChrFilter, hChrFilterPos, hChrFilterSize);
+ c->hcScale(c, dst1, dstWidth, src1, hChrFilter, hChrFilterPos, hChrFilterSize);
+ c->hcScale(c, dst2, dstWidth, src2, hChrFilter, hChrFilterPos, hChrFilterSize);
} else { // fast bilinear upscale / crap downscale
c->hcscale_fast(c, dst1, dst2, dstWidth, src1, src2, srcW, xInc);
}
@@ -2929,16 +2929,16 @@ static av_cold void sws_init_swScale_c(SwsContext *c)
if (c->srcBpc == 8) {
if (c->dstBpc <= 10) {
- c->hScale = hScale8To15_c;
+ c->hyScale = c->hcScale = hScale8To15_c;
if (c->flags & SWS_FAST_BILINEAR) {
c->hyscale_fast = hyscale_fast_c;
c->hcscale_fast = hcscale_fast_c;
}
} else {
- c->hScale = hScale8To19_c;
+ c->hyScale = c->hcScale = hScale8To19_c;
}
} else {
- c->hScale = c->dstBpc > 10 ? hScale16To19_c : hScale16To15_c;
+ c->hyScale = c->hcScale = c->dstBpc > 10 ? hScale16To19_c : hScale16To15_c;
}
if (c->srcRange != c->dstRange && !isAnyRGB(c->dstFormat)) {
diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h
index a936f96373..c572acb958 100644
--- a/libswscale/swscale_internal.h
+++ b/libswscale/swscale_internal.h
@@ -483,9 +483,14 @@ typedef struct SwsContext {
* (and input coefficients thus padded with zeroes)
* to simplify creating SIMD code.
*/
- void (*hScale)(struct SwsContext *c, int16_t *dst, int dstW, const uint8_t *src,
- const int16_t *filter, const int16_t *filterPos,
- int filterSize);
+ /** @{ */
+ void (*hyScale)(struct SwsContext *c, int16_t *dst, int dstW, const uint8_t *src,
+ const int16_t *filter, const int16_t *filterPos,
+ int filterSize);
+ void (*hcScale)(struct SwsContext *c, int16_t *dst, int dstW, const uint8_t *src,
+ const int16_t *filter, const int16_t *filterPos,
+ int filterSize);
+ /** @} */
void (*hScale16)(int16_t *dst, int dstW, const uint16_t *src, int srcW,
int xInc, const int16_t *filter, const int16_t *filterPos,
diff --git a/libswscale/x86/swscale_template.c b/libswscale/x86/swscale_template.c
index 4163647fa0..7ba1901e21 100644
--- a/libswscale/x86/swscale_template.c
+++ b/libswscale/x86/swscale_template.c
@@ -2474,7 +2474,7 @@ static av_cold void RENAME(sws_init_swScale)(SwsContext *c)
if (c->srcBpc == 8 && c->dstBpc <= 10) {
#if !COMPILE_TEMPLATE_MMX2
- c->hScale = RENAME(hScale );
+ c->hyScale = c->hcScale = RENAME(hScale );
#endif /* !COMPILE_TEMPLATE_MMX2 */
// Use the new MMX scaler if the MMX2 one can't be used (it is faster than the x86 ASM one).
diff --git a/tests/ref/fate/feeble-dxa b/tests/ref/fate/feeble-dxa
index 9013f99118..caea4c2e2a 100644
--- a/tests/ref/fate/feeble-dxa
+++ b/tests/ref/fate/feeble-dxa
@@ -62,4 +62,3 @@
0, 171000, 921600, 0x5639e670
1, 171429, 1000, 0xa491f3ef
1, 175510, 1000, 0x2c036e18
-1, 179592, 1000, 0x52d65e2a
diff --git a/tests/ref/fate/lmlm4-demux b/tests/ref/fate/lmlm4-demux
index 1d0d59f54d..f3214234d7 100644
--- a/tests/ref/fate/lmlm4-demux
+++ b/tests/ref/fate/lmlm4-demux
@@ -213,4 +213,3 @@
1, 265680, 768, 0xfd6c7597
0, 267267, 1327, 0x7d15307c
1, 267840, 768, 0x8d766d40
-0, 270270, 1225, 0x1b5d0f5f
diff --git a/tests/ref/fate/real-rv40 b/tests/ref/fate/real-rv40
index 990a530436..c63c525d08 100644
--- a/tests/ref/fate/real-rv40
+++ b/tests/ref/fate/real-rv40
@@ -1,121 +1,240 @@
0, 0, 276480, 0x5f7a0d4f
-0, 7500, 276480, 0x5f7a0d4f
-0, 15000, 276480, 0x5f7a0d4f
-0, 22500, 276480, 0x5f7a0d4f
-0, 30000, 276480, 0x5f7a0d4f
-0, 37500, 276480, 0x5f7a0d4f
-0, 45000, 276480, 0x5f7a0d4f
-0, 52500, 276480, 0x5f7a0d4f
-0, 60000, 276480, 0x5f7a0d4f
-0, 67500, 276480, 0x5f7a0d4f
-0, 75000, 276480, 0x5f7a0d4f
-0, 82500, 276480, 0x5f7a0d4f
-0, 90000, 276480, 0x5f7a0d4f
-0, 97500, 276480, 0x5f7a0d4f
-0, 105000, 276480, 0x5f7a0d4f
-0, 112500, 276480, 0x5f7a0d4f
-0, 120000, 276480, 0x5f7a0d4f
-0, 127500, 276480, 0x5f7a0d4f
-0, 135000, 276480, 0x75641594
-0, 142500, 276480, 0x32ee3526
-0, 150000, 276480, 0x5ce39368
-0, 157500, 276480, 0x4ec1e418
-0, 165000, 276480, 0x85cbc3b5
-0, 172500, 276480, 0x377c7b46
-0, 180000, 276480, 0x756a4a2e
-0, 187500, 276480, 0xcb379547
-0, 195000, 276480, 0x99c085be
-0, 202500, 276480, 0xe479ffed
-0, 210000, 276480, 0x1e4fae19
-0, 217500, 276480, 0x776412ef
-0, 225000, 276480, 0x58ce0f38
-0, 232500, 276480, 0x5ab69b27
-0, 240000, 276480, 0xc3db9706
-0, 247500, 276480, 0xc9c57884
-0, 255000, 276480, 0x000b5269
-0, 262500, 276480, 0x27ff7a5d
-0, 270000, 276480, 0x70647530
-0, 277500, 276480, 0x97612c4b
-0, 285000, 276480, 0xdf4e04d7
-0, 292500, 276480, 0xbd98f57c
-0, 300000, 276480, 0x5163b29b
-0, 307500, 276480, 0x99170e64
-0, 315000, 276480, 0x8a4e991f
-0, 322500, 276480, 0x6a45425f
-0, 330000, 276480, 0x7bf6b1ef
-0, 337500, 276480, 0x6de1e34b
-0, 345000, 276480, 0xdcaaa99a
-0, 352500, 276480, 0xd1e98808
-0, 360000, 276480, 0x6e2d524e
-0, 367500, 276480, 0x22c50a3d
-0, 375000, 276480, 0x62b76407
-0, 382500, 276480, 0x51e9b3eb
-0, 390000, 276480, 0x441f7afd
-0, 397500, 276480, 0xfb01efc6
-0, 405000, 276480, 0x294bb441
-0, 412500, 276480, 0xe04ac45e
-0, 420000, 276480, 0x58f275ea
-0, 427500, 276480, 0xf0b3b71b
-0, 435000, 276480, 0x674e34e4
-0, 442500, 276480, 0x41dda2d9
-0, 450000, 276480, 0xf46ba7fb
-0, 457500, 276480, 0x28b54815
-0, 465000, 276480, 0xaf2b5d89
-0, 472500, 276480, 0x8facba58
-0, 480000, 276480, 0x28a63236
-0, 487500, 276480, 0x1ad43fd7
-0, 495000, 276480, 0x71507bd2
-0, 502500, 276480, 0x35626022
-0, 510000, 276480, 0x7c1139b3
-0, 517500, 276480, 0x7fd73a99
-0, 525000, 276480, 0xb52e1aa2
-0, 532500, 276480, 0xd6f82cae
-0, 540000, 276480, 0xf88f75d4
-0, 547500, 276480, 0x04a8e3ee
-0, 555000, 276480, 0xa29f5b01
-0, 562500, 276480, 0x754ceaf5
-0, 570000, 276480, 0x5a38b4af
-0, 577500, 276480, 0xfcebc261
-0, 585000, 276480, 0x3d3ca985
-0, 592500, 276480, 0x94a03c75
-0, 600000, 276480, 0x2f98911c
-0, 607500, 276480, 0x923b9937
-0, 615000, 276480, 0xefab7ffd
-0, 622500, 276480, 0x6b9fbc80
-0, 630000, 276480, 0xe4bdbd1e
-0, 637500, 276480, 0x225a56c0
-0, 645000, 276480, 0xf58b1b7c
-0, 652500, 276480, 0xbaffcdcc
-0, 660000, 276480, 0xeb6eb88f
-0, 667500, 276480, 0xdb753d35
-0, 675000, 276480, 0xea80a82e
-0, 682500, 276480, 0x2aae902a
-0, 690000, 276480, 0x9b9ee961
-0, 697500, 276480, 0xaa12b6fd
-0, 705000, 276480, 0x50c31e73
-0, 712500, 276480, 0xdd9fb89f
-0, 720000, 276480, 0xaf82399a
-0, 727500, 276480, 0x7ce5f23c
-0, 735000, 276480, 0x5aaa7519
-0, 742500, 276480, 0xe45a5599
-0, 750000, 276480, 0x704411fb
-0, 757500, 276480, 0x9d7430a1
-0, 765000, 276480, 0x2c230702
-0, 772500, 276480, 0x4a4f76cd
-0, 780000, 276480, 0x27f54854
-0, 787500, 276480, 0x694d76e3
-0, 795000, 276480, 0x525463e2
-0, 802500, 276480, 0x819898f9
-0, 810000, 276480, 0xeeed00fc
-0, 817500, 276480, 0xb6f99ee3
-0, 825000, 276480, 0xefc83107
-0, 832500, 276480, 0xbb22e024
-0, 840000, 276480, 0x300f922a
-0, 847500, 276480, 0x826fc3bd
-0, 855000, 276480, 0x679a53f8
-0, 862500, 276480, 0x976c9e93
-0, 870000, 276480, 0xb194656e
-0, 877500, 276480, 0xf002c5ca
-0, 885000, 276480, 0xb243dda5
-0, 892500, 276480, 0x1700efbb
-0, 900000, 276480, 0x8f316c66
+0, 3754, 276480, 0x5f7a0d4f
+0, 7507, 276480, 0x5f7a0d4f
+0, 11261, 276480, 0x5f7a0d4f
+0, 15015, 276480, 0x5f7a0d4f
+0, 18769, 276480, 0x5f7a0d4f
+0, 22522, 276480, 0x5f7a0d4f
+0, 26276, 276480, 0x5f7a0d4f
+0, 30030, 276480, 0x5f7a0d4f
+0, 33784, 276480, 0x5f7a0d4f
+0, 37537, 276480, 0x5f7a0d4f
+0, 41291, 276480, 0x5f7a0d4f
+0, 45045, 276480, 0x5f7a0d4f
+0, 48799, 276480, 0x5f7a0d4f
+0, 52552, 276480, 0x5f7a0d4f
+0, 56306, 276480, 0x5f7a0d4f
+0, 60060, 276480, 0x5f7a0d4f
+0, 63814, 276480, 0x5f7a0d4f
+0, 67567, 276480, 0x5f7a0d4f
+0, 71321, 276480, 0x5f7a0d4f
+0, 75075, 276480, 0x5f7a0d4f
+0, 78829, 276480, 0x5f7a0d4f
+0, 82582, 276480, 0x5f7a0d4f
+0, 86336, 276480, 0x5f7a0d4f
+0, 90090, 276480, 0x5f7a0d4f
+0, 93844, 276480, 0x5f7a0d4f
+0, 97597, 276480, 0x5f7a0d4f
+0, 101351, 276480, 0x5f7a0d4f
+0, 105105, 276480, 0x5f7a0d4f
+0, 108859, 276480, 0x5f7a0d4f
+0, 112612, 276480, 0x5f7a0d4f
+0, 116366, 276480, 0x5f7a0d4f
+0, 120120, 276480, 0x5f7a0d4f
+0, 123874, 276480, 0x75641594
+0, 127627, 276480, 0x32ee3526
+0, 131381, 276480, 0xcb53479a
+0, 135135, 276480, 0x7ca9658e
+0, 138889, 276480, 0x5ce39368
+0, 142642, 276480, 0x4ec1e418
+0, 146396, 276480, 0xb3790499
+0, 150150, 276480, 0xa9f1506f
+0, 153904, 276480, 0x85cbc3b5
+0, 157657, 276480, 0x377c7b46
+0, 161411, 276480, 0x1a61d8db
+0, 165165, 276480, 0xe1de7f0a
+0, 168919, 276480, 0x756a4a2e
+0, 172672, 276480, 0xcb379547
+0, 176426, 276480, 0xbae14484
+0, 180180, 276480, 0x8e12331c
+0, 183934, 276480, 0x99c085be
+0, 187687, 276480, 0xe479ffed
+0, 191441, 276480, 0x99c82949
+0, 195195, 276480, 0xac7672dd
+0, 198949, 276480, 0x1e4fae19
+0, 202702, 276480, 0x776412ef
+0, 206456, 276480, 0x7d9b579f
+0, 210210, 276480, 0x1cd1ab29
+0, 213964, 276480, 0x58ce0f38
+0, 217717, 276480, 0x5ab69b27
+0, 221471, 276480, 0x0afad610
+0, 225225, 276480, 0x9eca3f11
+0, 228979, 276480, 0xc3db9706
+0, 232732, 276480, 0xc9c57884
+0, 236486, 276480, 0xd9fbb2cf
+0, 240240, 276480, 0xdc07f3c9
+0, 243994, 276480, 0x000b5269
+0, 247747, 276480, 0x27ff7a5d
+0, 251501, 276480, 0xd92e2017
+0, 255255, 276480, 0x18d4b27d
+0, 259009, 276480, 0x70647530
+0, 262762, 276480, 0x97612c4b
+0, 266516, 276480, 0xc9d4ac78
+0, 270270, 276480, 0x4ec4d57f
+0, 274024, 276480, 0xdf4e04d7
+0, 277777, 276480, 0xbd98f57c
+0, 281531, 276480, 0x7247ea3e
+0, 285285, 276480, 0xa5d670ec
+0, 289039, 276480, 0x5163b29b
+0, 292792, 276480, 0x99170e64
+0, 296546, 276480, 0x37f4c0b0
+0, 300300, 276480, 0x7a4f2561
+0, 304053, 276480, 0x8a4e991f
+0, 307807, 276480, 0x6a45425f
+0, 311561, 276480, 0x1f0e2bb6
+0, 315315, 276480, 0xd75482c6
+0, 319068, 276480, 0x7bf6b1ef
+0, 322822, 276480, 0x6de1e34b
+0, 326576, 276480, 0x4526c89b
+0, 330330, 276480, 0xf964e18e
+0, 334083, 276480, 0xdcaaa99a
+0, 337837, 276480, 0xd1e98808
+0, 341591, 276480, 0x556b2365
+0, 345345, 276480, 0x0cf65540
+0, 349098, 276480, 0x6e2d524e
+0, 352852, 276480, 0x22c50a3d
+0, 356606, 276480, 0x293f19af
+0, 360360, 276480, 0xf4b1c461
+0, 364113, 276480, 0x62b76407
+0, 367867, 276480, 0x51e9b3eb
+0, 371621, 276480, 0x7b910bc7
+0, 375375, 276480, 0x6dd14ca6
+0, 379128, 276480, 0x441f7afd
+0, 382882, 276480, 0xfb01efc6
+0, 386636, 276480, 0x4f73ccea
+0, 390390, 276480, 0x5ac8e06f
+0, 394143, 276480, 0x294bb441
+0, 397897, 276480, 0xe04ac45e
+0, 401651, 276480, 0xa7a38d41
+0, 405405, 276480, 0xf688a3ed
+0, 409158, 276480, 0x58f275ea
+0, 412912, 276480, 0xf0b3b71b
+0, 416666, 276480, 0x3ce773bf
+0, 420420, 276480, 0x01840548
+0, 424173, 276480, 0x674e34e4
+0, 427927, 276480, 0x41dda2d9
+0, 431681, 276480, 0xc5b60838
+0, 435435, 276480, 0x9b209f41
+0, 439188, 276480, 0xf46ba7fb
+0, 442942, 276480, 0x28b54815
+0, 446696, 276480, 0xb605a933
+0, 450450, 276480, 0x34484aff
+0, 454203, 276480, 0xaf2b5d89
+0, 457957, 276480, 0x8facba58
+0, 461711, 276480, 0xbbe3e99f
+0, 465465, 276480, 0x02162c7c
+0, 469218, 276480, 0x28a63236
+0, 472972, 276480, 0x1ad43fd7
+0, 476726, 276480, 0xe37883e5
+0, 480480, 276480, 0x2b8a89c5
+0, 484233, 276480, 0x71507bd2
+0, 487987, 276480, 0x35626022
+0, 491741, 276480, 0x461fc3e7
+0, 495495, 276480, 0xce5af1ec
+0, 499248, 276480, 0x7c1139b3
+0, 503002, 276480, 0x7fd73a99
+0, 506756, 276480, 0x4ae4c3a6
+0, 510510, 276480, 0xcb60725a
+0, 514263, 276480, 0xb52e1aa2
+0, 518017, 276480, 0xd6f82cae
+0, 521771, 276480, 0x6310e665
+0, 525525, 276480, 0xfa88a483
+0, 529278, 276480, 0xf88f75d4
+0, 533032, 276480, 0x04a8e3ee
+0, 536786, 276480, 0x54766a12
+0, 540540, 276480, 0x0b41f0d7
+0, 544293, 276480, 0xa29f5b01
+0, 548047, 276480, 0x754ceaf5
+0, 551801, 276480, 0x150c0423
+0, 555555, 276480, 0xde084059
+0, 559308, 276480, 0x5a38b4af
+0, 563062, 276480, 0xfcebc261
+0, 566816, 276480, 0x0eb9770d
+0, 570570, 276480, 0x046394ae
+0, 574323, 276480, 0x3d3ca985
+0, 578077, 276480, 0x94a03c75
+0, 581831, 276480, 0x800eea2d
+0, 585585, 276480, 0x6a841f41
+0, 589338, 276480, 0x2f98911c
+0, 593092, 276480, 0x923b9937
+0, 596846, 276480, 0xe82f8e0f
+0, 600600, 276480, 0xee82d657
+0, 604353, 276480, 0xefab7ffd
+0, 608107, 276480, 0x6b9fbc80
+0, 611861, 276480, 0x4a1ada47
+0, 615614, 276480, 0x6d4b49d7
+0, 619368, 276480, 0xe4bdbd1e
+0, 623122, 276480, 0x225a56c0
+0, 626876, 276480, 0xd4adadad
+0, 630629, 276480, 0xff4e1a8c
+0, 634383, 276480, 0xf58b1b7c
+0, 638137, 276480, 0xbaffcdcc
+0, 641891, 276480, 0x374f88f0
+0, 645644, 276480, 0x3d861ae6
+0, 649398, 276480, 0xeb6eb88f
+0, 653152, 276480, 0xdb753d35
+0, 656906, 276480, 0x9aa543af
+0, 660659, 276480, 0xb24c8016
+0, 664413, 276480, 0xea80a82e
+0, 668167, 276480, 0x2aae902a
+0, 671921, 276480, 0x5bba3cfb
+0, 675674, 276480, 0x5c6e97a9
+0, 679428, 276480, 0x9b9ee961
+0, 683182, 276480, 0xaa12b6fd
+0, 686936, 276480, 0xe9d2439f
+0, 690689, 276480, 0xbf09053c
+0, 694443, 276480, 0x50c31e73
+0, 698197, 276480, 0xdd9fb89f
+0, 701951, 276480, 0x3e4e5aec
+0, 705704, 276480, 0x0b752d28
+0, 709458, 276480, 0xaf82399a
+0, 713212, 276480, 0x7ce5f23c
+0, 716966, 276480, 0xad135d0f
+0, 720719, 276480, 0x55dadd30
+0, 724473, 276480, 0x5aaa7519
+0, 728227, 276480, 0xe45a5599
+0, 731981, 276480, 0xc8e89913
+0, 735734, 276480, 0x2f447fd3
+0, 739488, 276480, 0x704411fb
+0, 743242, 276480, 0x9d7430a1
+0, 746996, 276480, 0x24dd5fd3
+0, 750749, 276480, 0x51cb657c
+0, 754503, 276480, 0x2c230702
+0, 758257, 276480, 0x4a4f76cd
+0, 762011, 276480, 0xdcd71e88
+0, 765764, 276480, 0x87160f99
+0, 769518, 276480, 0x27f54854
+0, 773272, 276480, 0x694d76e3
+0, 777026, 276480, 0xcbe93c19
+0, 780779, 276480, 0x50742e1b
+0, 784533, 276480, 0x525463e2
+0, 788287, 276480, 0x819898f9
+0, 792041, 276480, 0x08fac755
+0, 795794, 276480, 0x35c46927
+0, 799548, 276480, 0xeeed00fc
+0, 803302, 276480, 0xb6f99ee3
+0, 807056, 276480, 0xd87f4c73
+0, 810809, 276480, 0xde97d9fd
+0, 814563, 276480, 0xefc83107
+0, 818317, 276480, 0xbb22e024
+0, 822071, 276480, 0x53a7cfcb
+0, 825824, 276480, 0xbe1fbb19
+0, 829578, 276480, 0x300f922a
+0, 833332, 276480, 0x826fc3bd
+0, 837086, 276480, 0x679aa57a
+0, 840839, 276480, 0x5497097b
+0, 844593, 276480, 0x679a53f8
+0, 848347, 276480, 0x976c9e93
+0, 852101, 276480, 0xe80f87f2
+0, 855854, 276480, 0xdc2d7c6c
+0, 859608, 276480, 0xb194656e
+0, 863362, 276480, 0xf002c5ca
+0, 867116, 276480, 0x43fc1c64
+0, 870869, 276480, 0xf62d8581
+0, 874623, 276480, 0xb243dda5
+0, 878377, 276480, 0x1700efbb
+0, 882131, 276480, 0x9ebe6ba2
+0, 885884, 276480, 0x8f316c66
+0, 889638, 276480, 0x6348ecf5
+0, 893392, 276480, 0x34b5b78a
+0, 897146, 276480, 0xcbf66922
diff --git a/tests/ref/fate/rv30 b/tests/ref/fate/rv30
index 6c99871eb6..a3c5dcfbbf 100644
--- a/tests/ref/fate/rv30
+++ b/tests/ref/fate/rv30
@@ -1,46 +1,109 @@
0, 0, 126720, 0xcefaec47
-0, 7500, 126720, 0xa416ece5
-0, 15000, 126720, 0xa416ece5
-0, 22500, 126720, 0xa416ece5
-0, 30000, 126720, 0xcc10f4b7
-0, 37500, 126720, 0xeb6fb8d7
-0, 45000, 126720, 0xda71b917
-0, 52500, 126720, 0xbb1abbb7
-0, 60000, 126720, 0x273fbc37
-0, 67500, 126720, 0x16eebbd7
-0, 75000, 126720, 0x105eb927
-0, 82500, 126720, 0x7fa3ae27
-0, 90000, 126720, 0xd115a757
-0, 97500, 126720, 0x04e7897c
-0, 105000, 126720, 0x68cfda2b
-0, 112500, 126720, 0xe572dfc9
-0, 120000, 126720, 0xbc3cc34f
-0, 127500, 126720, 0xcf8cb0e2
-0, 135000, 126720, 0x75ae61b6
-0, 142500, 126720, 0x554fe3e4
-0, 150000, 126720, 0x72ecea95
-0, 157500, 126720, 0x5d00b5fe
-0, 165000, 126720, 0xe39bba0d
-0, 172500, 126720, 0x9c21bad8
-0, 180000, 126720, 0x72f2a47d
-0, 187500, 126720, 0x4f639ebe
-0, 195000, 126720, 0x534a10cc
-0, 202500, 126720, 0xfdca11d3
-0, 210000, 126720, 0x0c735615
-0, 217500, 126720, 0x0eaf0c1b
-0, 225000, 126720, 0xce5e6794
-0, 232500, 126720, 0x14cf7974
-0, 240000, 126720, 0xbc513f2a
-0, 247500, 126720, 0xbc303fae
-0, 255000, 126720, 0xd9f67585
-0, 262500, 126720, 0x3378251f
-0, 270000, 126720, 0xb3ed5911
-0, 277500, 126720, 0xc15a3577
-0, 285000, 126720, 0x0a24f256
-0, 292500, 126720, 0xfab9c45d
-0, 300000, 126720, 0x45464610
-0, 307500, 126720, 0xfe2e057d
-0, 315000, 126720, 0x23efdc35
-0, 322500, 126720, 0x4d888b2e
-0, 330000, 126720, 0xdd0d74df
-0, 337500, 126720, 0x08382b8e
+0, 3003, 126720, 0xa416ece5
+0, 6006, 126720, 0xa416ece5
+0, 9009, 126720, 0xa416ece5
+0, 12012, 126720, 0x60d6ed27
+0, 15015, 126720, 0x259af497
+0, 18018, 126720, 0x5e6ff4d7
+0, 21021, 126720, 0xcc10f4b7
+0, 24024, 126720, 0x763ab817
+0, 27027, 126720, 0xeb6fb8d7
+0, 30030, 126720, 0xda71b917
+0, 33033, 126720, 0x0967b8f7
+0, 36036, 126720, 0x4b62b947
+0, 39039, 126720, 0xbb1abbb7
+0, 42042, 126720, 0x273fbc37
+0, 45045, 126720, 0x16eebbd7
+0, 48048, 126720, 0x105eb927
+0, 51051, 126720, 0x7fa3ae27
+0, 54054, 126720, 0x722e99f7
+0, 57057, 126720, 0x5ac9a827
+0, 60060, 126720, 0x07beba77
+0, 63063, 126720, 0x29d6a887
+0, 66066, 126720, 0xa5caab87
+0, 69069, 126720, 0x9ca7aac7
+0, 72072, 126720, 0xb7debcd7
+0, 75075, 126720, 0xd115a757
+0, 78078, 126720, 0x6ddaef32
+0, 81081, 126720, 0xde1bb900
+0, 84084, 126720, 0xac6c071b
+0, 87087, 126720, 0x04e7897c
+0, 90090, 126720, 0x5eee050f
+0, 93093, 126720, 0xe675be59
+0, 96096, 126720, 0xdc3e0837
+0, 99099, 126720, 0x68cfda2b
+0, 102102, 126720, 0xe572dfc9
+0, 105105, 126720, 0x582fb176
+0, 108108, 126720, 0xa9477df0
+0, 111111, 126720, 0xbc3cc34f
+0, 114114, 126720, 0xcf8cb0e2
+0, 117117, 126720, 0xcff1db35
+0, 120120, 126720, 0xc6e10f9f
+0, 123123, 126720, 0x75ae61b6
+0, 126126, 126720, 0x12af3119
+0, 129129, 126720, 0x85597543
+0, 132132, 126720, 0x68c27aca
+0, 135135, 126720, 0x554fe3e4
+0, 138138, 126720, 0x72ecea95
+0, 141141, 126720, 0xf4d003d1
+0, 144144, 126720, 0x9bf6a605
+0, 147147, 126720, 0x5d00b5fe
+0, 150150, 126720, 0x93f7b040
+0, 153153, 126720, 0x0d6ad154
+0, 156156, 126720, 0x4be8b4ea
+0, 159159, 126720, 0xe39bba0d
+0, 162162, 126720, 0x9c21bad8
+0, 165165, 126720, 0xa567f25b
+0, 168168, 126720, 0x7a82663a
+0, 171171, 126720, 0x72f2a47d
+0, 174174, 126720, 0x4f639ebe
+0, 177177, 126720, 0xab0fce83
+0, 180180, 126720, 0x6cf87d39
+0, 183183, 126720, 0x534a10cc
+0, 186186, 126720, 0x6bbcf44c
+0, 189189, 126720, 0xfdca11d3
+0, 192192, 126720, 0x7e58f5a6
+0, 195195, 126720, 0x5fd753d8
+0, 198198, 126720, 0x0c735615
+0, 201201, 126720, 0x2a034ebf
+0, 204204, 126720, 0xeaf3dd0b
+0, 207207, 126720, 0x0eaf0c1b
+0, 210210, 126720, 0xce5e6794
+0, 213213, 126720, 0xf27c31c3
+0, 216216, 126720, 0xb64af168
+0, 219219, 126720, 0x14cf7974
+0, 222222, 126720, 0x1c2a513d
+0, 225225, 126720, 0xa3f515ab
+0, 228228, 126720, 0xcfd62765
+0, 231231, 126720, 0xbc513f2a
+0, 234234, 126720, 0xbc303fae
+0, 237237, 126720, 0x2f8f69b9
+0, 240240, 126720, 0x0a22cc69
+0, 243243, 126720, 0xd9f67585
+0, 246246, 126720, 0x20403001
+0, 249249, 126720, 0xf92b2a25
+0, 252252, 126720, 0x3c170aad
+0, 255255, 126720, 0x3378251f
+0, 258258, 126720, 0xb3ed5911
+0, 261261, 126720, 0x35d24ef8
+0, 264264, 126720, 0x8da30275
+0, 267267, 126720, 0xc15a3577
+0, 270270, 126720, 0xf2942f53
+0, 273273, 126720, 0x44d8304a
+0, 276276, 126720, 0xd688a932
+0, 279279, 126720, 0x0a24f256
+0, 282282, 126720, 0xfab9c45d
+0, 285285, 126720, 0x10e939ce
+0, 288288, 126720, 0x97fcaa3a
+0, 291291, 126720, 0x45464610
+0, 294294, 126720, 0xfe2e057d
+0, 297297, 126720, 0x0b6718ae
+0, 300300, 126720, 0x5284da7b
+0, 303303, 126720, 0x23efdc35
+0, 306306, 126720, 0xc387b2b3
+0, 309309, 126720, 0xc9e92bf1
+0, 312312, 126720, 0xfbf20a01
+0, 315315, 126720, 0x4d888b2e
+0, 318318, 126720, 0xdd0d74df
+0, 321321, 126720, 0x49d07aa4
+0, 324324, 126720, 0x08382b8e