diff -ruNX mplayer-exclude mplayer-svn/cfg-common.h mplayer-svn-monty/cfg-common.h --- mplayer-svn/cfg-common.h 2009-07-18 17:24:42.684913261 -0400 +++ mplayer-svn-monty/cfg-common.h 2009-07-12 01:14:44.072146355 -0400 @@ -173,6 +173,7 @@ extern const m_config_t dvbin_opts_conf[]; extern const m_option_t lavfdopts_conf[]; +extern const m_option_t theora_decode_opts_conf[]; extern int rtspStreamOverTCP; extern int rtsp_transport_tcp; diff -ruNX mplayer-exclude mplayer-svn/cfg-common-opts.h mplayer-svn-monty/cfg-common-opts.h --- mplayer-svn/cfg-common-opts.h 2009-07-18 17:24:42.691910426 -0400 +++ mplayer-svn-monty/cfg-common-opts.h 2009-07-12 01:14:22.035167924 -0400 @@ -269,6 +269,7 @@ #ifdef CONFIG_XVID4 {"xvidopts", xvid_dec_opts, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, #endif + {"theoradopts", theora_decode_opts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, {"codecs-file", &codecs_file, CONF_TYPE_STRING, 0, 0, 0, NULL}, // ------------------------- subtitles options -------------------- diff -ruNX mplayer-exclude mplayer-svn/cfg-mplayer.h mplayer-svn-monty/cfg-mplayer.h --- mplayer-svn/cfg-mplayer.h 2009-07-18 17:24:42.680908689 -0400 +++ mplayer-svn-monty/cfg-mplayer.h 2009-07-15 12:34:21.215150252 -0400 @@ -244,6 +244,7 @@ //---------------------- mplayer-only options ------------------------ + {"fast", &fast, CONF_TYPE_FLAG, CONF_GLOBAL, 0, 1, NULL}, {"use-filedir-conf", &use_filedir_conf, CONF_TYPE_FLAG, CONF_GLOBAL, 0, 1, NULL}, {"nouse-filedir-conf", &use_filedir_conf, CONF_TYPE_FLAG, CONF_GLOBAL, 1, 0, NULL}, #ifdef CONFIG_CRASH_DEBUG diff -ruNX mplayer-exclude mplayer-svn/etc/codecs.conf mplayer-svn-monty/etc/codecs.conf --- mplayer-svn/etc/codecs.conf 2009-07-18 17:26:18.523908271 -0400 +++ mplayer-svn-monty/etc/codecs.conf 2009-07-18 17:28:05.690942095 -0400 @@ -527,7 +527,7 @@ fourcc theo,Thra driver theora dll libtheora - out YV12 + out YV12,422P,444P ; prefer native codecs over win32? ; the win32 codecs probably are (better) optimized and support direct diff -ruNX mplayer-exclude mplayer-svn/libaf/af.c mplayer-svn-monty/libaf/af.c --- mplayer-svn/libaf/af.c 2009-07-18 17:24:40.696912726 -0400 +++ mplayer-svn-monty/libaf/af.c 2009-07-15 06:05:46.344197653 -0400 @@ -50,6 +50,7 @@ extern af_info_t af_info_scaletempo; extern af_info_t af_info_stats; extern af_info_t af_info_bs2b; +extern af_info_t af_info_yuv4ogg; static af_info_t* filter_list[]={ &af_info_dummy, @@ -88,6 +89,7 @@ #ifdef CONFIG_LIBBS2B &af_info_bs2b, #endif + &af_info_yuv4ogg, NULL }; @@ -157,6 +159,7 @@ mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Adding filter %s \n",name); // Initialize the new filter + new->cmdline = (cmdline?strdup(cmdline):NULL); if(AF_OK == new->info->open(new) && AF_ERROR < new->control(new,AF_CONTROL_POST_CREATE,&s->cfg)){ if(cmdline){ @@ -246,6 +249,7 @@ // Uninitialize af and free memory af->uninit(af); + if(af->cmdline)free(af->cmdline); free(af); } diff -ruNX mplayer-exclude mplayer-svn/libaf/af_format.c mplayer-svn-monty/libaf/af_format.c --- mplayer-svn/libaf/af_format.c 2009-07-18 17:24:39.023898695 -0400 +++ mplayer-svn-monty/libaf/af_format.c 2009-07-15 05:43:34.456315849 -0400 @@ -40,17 +40,6 @@ #include "af_format_ulaw.h" #include "af_format_alaw.h" -// Switch endianness -static void endian(void* in, void* out, int len, int bps); -// From signed to unsigned and the other way -static void si2us(void* data, int len, int bps); -// Change the number of bits per sample -static void change_bps(void* in, void* out, int len, int inbps, int outbps); -// From float to int signed -static void float2int(float* in, void* out, int len, int bps); -// From signed int to float -static void int2float(void* in, float* out, int len, int bps); - static af_data_t* play(struct af_instance_s* af, af_data_t* data); static af_data_t* play_swapendian(struct af_instance_s* af, af_data_t* data); static af_data_t* play_float_s16(struct af_instance_s* af, af_data_t* data); @@ -356,7 +345,7 @@ } // Function implementations used by play -static void endian(void* in, void* out, int len, int bps) +void endian(void* in, void* out, int len, int bps) { register int i; switch(bps){ @@ -386,7 +375,7 @@ } } -static void si2us(void* data, int len, int bps) +void si2us(void* data, int len, int bps) { register long i = -(len * bps); register uint8_t *p = &((uint8_t *)data)[len * bps]; @@ -399,7 +388,7 @@ } while (i += bps); } -static void change_bps(void* in, void* out, int len, int inbps, int outbps) +void change_bps(void* in, void* out, int len, int inbps, int outbps) { register int i; switch(inbps){ @@ -470,7 +459,7 @@ } } -static void float2int(float* in, void* out, int len, int bps) +void float2int(float* in, void* out, int len, int bps) { register int i; switch(bps){ @@ -493,7 +482,7 @@ } } -static void int2float(void* in, float* out, int len, int bps) +void int2float(void* in, float* out, int len, int bps) { register int i; switch(bps){ diff -ruNX mplayer-exclude mplayer-svn/libaf/af_format.h mplayer-svn-monty/libaf/af_format.h --- mplayer-svn/libaf/af_format.h 2009-07-18 17:24:39.817940192 -0400 +++ mplayer-svn-monty/libaf/af_format.h 2009-07-15 05:41:57.017181569 -0400 @@ -110,4 +110,16 @@ char* af_fmt2str(int format, char* str, int size); const char* af_fmt2str_short(int format); +// Switch endianness +extern void endian(void* in, void* out, int len, int bps); +// From signed to unsigned and the other way +extern void si2us(void* data, int len, int bps); +// Change the number of bits per sample +extern void change_bps(void* in, void* out, int len, int inbps, int outbps); +// From float to int signed +extern void float2int(float* in, void* out, int len, int bps); +// From signed int to float +extern void int2float(void* in, float* out, int len, int bps); + + #endif /* MPLAYER_AF_FORMAT_H */ diff -ruNX mplayer-exclude mplayer-svn/libaf/af.h mplayer-svn-monty/libaf/af.h --- mplayer-svn/libaf/af.h 2009-07-18 17:24:40.700838514 -0400 +++ mplayer-svn-monty/libaf/af.h 2009-07-15 06:01:51.814315155 -0400 @@ -51,6 +51,7 @@ int nch; // number of channels int format; // format int bps; // bytes per sample + double pts; // presentation time of this block } af_data_t; @@ -74,6 +75,7 @@ typedef struct af_instance_s { af_info_t* info; + char *cmdline; int (*control)(struct af_instance_s* af, int cmd, void* arg); void (*uninit)(struct af_instance_s* af); af_data_t* (*play)(struct af_instance_s* af, af_data_t* data); diff -ruNX mplayer-exclude mplayer-svn/libaf/af_yuv4ogg.c mplayer-svn-monty/libaf/af_yuv4ogg.c --- mplayer-svn/libaf/af_yuv4ogg.c 1969-12-31 19:00:00.000000000 -0500 +++ mplayer-svn-monty/libaf/af_yuv4ogg.c 2009-08-10 03:53:36.666738396 -0400 @@ -0,0 +1,347 @@ +/* + * + * af_yuv4ogg, part of MPlayer + * + * Copyright (C) 2009 Monty + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Postfish; see the file COPYING. If not, write to the + * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +/* yuv4ogg format interleaves multiple media stream types into a + single fully timed output stream such that it can be used for + inter-tool interchange over a single pipe. This audio filter finds + the yuv4ogg stream in use and interleaves audio into it. */ + +#include +#include +#include +#include +#include + +#include "af.h" +#include "libmpcodecs/vf_yuv4ogg.h" +#include "af_format.h" +#include "af_format_ulaw.h" +#include "af_format_alaw.h" +#include "libvo/fastmemcpy.h" + +/* buffering in the event we need to swallow frames before another y4o + plugin is ready to write a header */ +struct audio_buffer { + af_data_t* data; + struct audio_buffer *next; +}; + +typedef struct { + struct y4o_file_entry *entry; + int stream_num; + + struct audio_buffer *buffer; + int can_start; + int disabled; + + // Buffer for output to file, not output to next filter + af_data_t a; + +} af_y4o_t; + +static int af_y4o_ready(af_y4o_t *p){ + return p->can_start; +} + +static void af_y4o_start(af_y4o_t *p){ + fprintf(p->entry->fd,"AUDIO R%d C%d\n", + p->a.rate, p->a.nch); // always LE signed 24 bit output +} + +static void af_y4o_exit(af_y4o_t *p){ + struct audio_buffer *b=p->buffer; + while(b){ + struct audio_buffer *next=b->next; + if(b->data){ + if(b->data->audio) + free(b->data->audio); + free(b->data); + } + free(b); + b=next; + } + free(p); +} + +static void af_y4o_write(af_y4o_t *p, const unsigned char *ptr, const size_t num_bytes) +{ + if (fwrite(ptr, 1, num_bytes, p->entry->fd) != num_bytes){ + mp_msg(MSGT_AFILTER,MSGL_ERR,"\n[yuv4ogg] Write error: %s\n",strerror(errno)); + mp_msg(MSGT_AFILTER,MSGL_ERR," Aborting stream\n"); + p->disabled=1; + } +} + +// By the time we get here, our data format is already sanitized +static void af_y4o_write_frame(struct af_instance_s* af, af_data_t* data){ + af_y4o_t *p = (af_y4o_t *)af->setup; + if(data->len>0){ + fprintf(p->entry->fd,"FRAME S%d L%d P%.3f\n",p->stream_num,data->len,data->pts); + af_y4o_write(p,data->audio,data->len); + } +} + +static int af_y4o_control(struct af_instance_s* af, int cmd, void* arg){ + + switch(cmd){ + case AF_CONTROL_REINIT: + // Sanity check + if(!arg) return AF_ERROR; + + af->data->rate = ((af_data_t*)arg)->rate; + af->data->nch = ((af_data_t*)arg)->nch; + af->data->format = ((af_data_t*)arg)->format; + af->data->bps = ((af_data_t*)arg)->bps; + return af_test_output(af,(af_data_t*)arg); + } + + return AF_UNKNOWN; +} + +static void af_y4o_uninit(struct af_instance_s* af){ + af_y4o_t *p = (af_y4o_t *)af->setup; + mp_msg(MSGT_AFILTER, MSGL_INFO, + "[yuv4ogg] suspending %s stream %d\n",p->entry->filename,p->stream_num); + + y4o_restart(); + + // data needs to be freed, but not priv + if(af->data) + free(af->data); + + if(p->a.audio) + free(p->a.audio); + p->a.audio=NULL; +} + +static af_data_t* af_y4o_play(struct af_instance_s* af, af_data_t* data){ + af_y4o_t *p = (af_y4o_t *)af->setup; + af_data_t *a = &p->a; + int s = data->len/data->bps/data->nch; // Number of sample in data chunk + int len = data->len/data->bps; + int nalen; + + if(p->disabled) return data; + + if(!p->can_start){ + /* our first frame; save the unalterable aspects of the format */ + a->rate = data->rate; + a->nch = data->nch; + a->format = AF_FORMAT_S24_LE; + a->bps = 3; + p->can_start=1; + }else{ + if(a->rate != data->rate || + a->nch != data->nch){ + mp_msg(MSGT_AFILTER,MSGL_ERR,"\n[yuv4ogg] ERROR: Audio format (%d,%d != %d,%d)changed for %s stream %d\n", + data->rate,data->nch,a->rate,a->nch,p->entry->filename,p->stream_num); + mp_msg(MSGT_AFILTER,MSGL_ERR," Aborting stream\n"); + p->disabled=1; + } + } + + nalen = data->len / data->bps * a->bps; + // If there is a buffer free it + if(a->audio) + free(a->audio); + // Create new buffer and check that it is OK + a->audio = malloc(nalen); + if(!a->audio){ + mp_msg(MSGT_AFILTER, MSGL_FATAL, "[yuv4ogg] ERROR: Could not allocate memory; aborting\n"); + p->disabled=1; + return data; + } + a->len=nalen; + a->pts=data->pts; + + // Change passthrough to cpu native endian format + if((data->format&AF_FORMAT_END_MASK)!=AF_FORMAT_NE) + endian(data->audio,data->audio,len,data->bps); + + if((data->format & AF_FORMAT_SPECIAL_MASK) == AF_FORMAT_MU_LAW) { + // from ULAW + from_ulaw(data->audio, a->audio, len, a->bps, a->format&AF_FORMAT_POINT_MASK); + } else if((data->format & AF_FORMAT_SPECIAL_MASK) == AF_FORMAT_A_LAW) { + // from ALAW + from_alaw(data->audio, a->audio, len, a->bps, a->format&AF_FORMAT_POINT_MASK); + } else if((data->format & AF_FORMAT_POINT_MASK) == AF_FORMAT_F) { + // from float + float2int(data->audio, a->audio, len, a->bps); + } else { + // from int + + // Change signed/unsigned + if((data->format&AF_FORMAT_SIGN_MASK) != (a->format&AF_FORMAT_SIGN_MASK)){ + si2us(data->audio,len,data->bps); + } + + // Change the number of bits + if(data->bps != a->bps) + change_bps(data->audio,a->audio,len,data->bps,a->bps); + else + fast_memcpy(a->audio,data->audio,len*a->bps); + + // re-change signed/unsigned + if((data->format&AF_FORMAT_SIGN_MASK) != (a->format&AF_FORMAT_SIGN_MASK)){ + si2us(data->audio,len,data->bps); + } + + } + + // Return passthrough to original endianness; leave no footprint + if((data->format&AF_FORMAT_END_MASK)!=AF_FORMAT_NE) + endian(data->audio,data->audio,len,data->bps); + + if(!y4o_start(p->entry)){ + /* another plugin is not ready to write its header... no choice + but to buffer this frame */ + + struct audio_buffer *b = calloc(1,sizeof(*b)); + af_data_t *ba = calloc(1,sizeof(*ba)); + void *d = malloc(3*s*data->nch); + + mp_msg(MSGT_AFILTER, MSGL_INFO, + "\n[yuv4ogg] Stream %d buffering frame waiting for other streams...\n", p->stream_num); + + if(!b || !ba || !d){ + if(b)free(b); + if(ba)free(ba); + if(d)free(d); + + mp_msg(MSGT_AFILTER, MSGL_FATAL, + "\n[yuv4ogg] failed to buffer frame while waiting for initialization!\n"); + }else{ + memcpy(ba,a,sizeof(*ba)); + ba->audio = d; + memcpy(ba->audio, a->audio, a->len); + b->data=ba; + b->next = p->buffer; + p->buffer = b; + } + }else{ + /* write any buffered frames */ + if(p->buffer){ + struct audio_buffer *b=p->buffer; + p->buffer=NULL; + + mp_msg(MSGT_AFILTER, MSGL_INFO, + "\n[yuv4ogg] Stream %d done waiting, writing buffered frames...\n", p->stream_num); + + while(b){ + struct audio_buffer *next=b->next; + b->next=p->buffer; + p->buffer=b; + b=next; + } + + b=p->buffer; + p->buffer=NULL; + while(b){ + struct audio_buffer *next=b->next; + af_y4o_write_frame(af,b->data); + if(b->data){ + if(b->data->audio) + free(b->data->audio); + free(b->data); + } + free(b); + b=next; + } + } + /* write this frame */ + af_y4o_write_frame(af,a); + } + + return data; +} + +static int af_y4o_open(af_instance_t* af){ + af_y4o_t *p; + struct y4o_callback_entry *c; + char *args = af->cmdline; + struct y4o_file_entry *entry; + + mp_msg(MSGT_AFILTER, MSGL_INFO, + "[yuv4ogg] opening with args %s\n",args?args:"(none)"); + entry = y4o_fetch_entry(args); + + if(entry->started){ + /* reinitialization case */ + int i,stream_num = entry->stream_counter-1; + c = entry->stream; + for(i=0;inext; + if(!c){ + mp_msg(MSGT_AFILTER, MSGL_FATAL, + "[yuv4ogg] unable to add new stream to file %s after playback started\n",entry->filename); + return 0; + } + p=af->setup=c->priv; + mp_msg(MSGT_VFILTER, MSGL_INFO, + "[yuv4ogg] restarting as %s stream %d\n",entry->filename,stream_num); + + }else{ + c=calloc(1,sizeof(*c)); + if(!c) return AF_ERROR; + + p=af->setup=calloc(1,sizeof(af_y4o_t)); + if(!p) return AF_ERROR; + + memset(&p->a,0,sizeof(p->a)); + p->entry=entry; + p->stream_num = p->entry->stream_counter-1; + c->ready = (int (*)(void *))af_y4o_ready; + c->start = (void (*)(void *))af_y4o_start; + c->exit = (void (*)(void *))af_y4o_exit; + c->priv = p; + c->next = entry->stream; + entry->stream=c; + + mp_msg(MSGT_AFILTER, MSGL_INFO, + "[yuv4ogg] starting as %s stream %d\n",entry->filename,p->stream_num); + } + + af->control=af_y4o_control; + af->uninit=af_y4o_uninit; + af->play=af_y4o_play; + af->mul=1; + af->data=calloc(1,sizeof(af_data_t)); + + if(af->data == NULL) + return AF_ERROR; + + p->disabled=0; + return AF_OK; +} + +// Description of this filter +af_info_t af_info_yuv4ogg = { + "Output audio frames to yuv4ogg", + "yuv4ogg", + "Monty", + "", + 0, + af_y4o_open +}; + + diff -ruNX mplayer-exclude mplayer-svn/libao2/ao_null.c mplayer-svn-monty/libao2/ao_null.c --- mplayer-svn/libao2/ao_null.c 2009-07-18 17:24:06.164908572 -0400 +++ mplayer-svn-monty/libao2/ao_null.c 2009-07-15 13:16:34.667517737 -0400 @@ -27,6 +27,9 @@ #include "audio_out.h" #include "audio_out_internal.h" +extern int fast; +extern int vo_pts; + static const ao_info_t info = { "Null audio output", @@ -71,9 +74,8 @@ static int init(int rate,int channels,int format,int flags){ int samplesize = af_fmt2bits(format) / 8; - ao_data.outburst = 256 * channels * samplesize; - // A "buffer" for about 0.2 seconds of audio - ao_data.buffersize = (int)(rate * 0.2 / 256 + 1) * ao_data.outburst; + ao_data.outburst = 8192; + ao_data.buffersize = 8192; ao_data.channels=channels; ao_data.samplerate=rate; ao_data.format=format; @@ -109,25 +111,34 @@ // return: how many bytes can be played without blocking static int get_space(void){ - drain(); - return ao_data.buffersize - buffer; + if(fast) + if(vo_pts) + return ao_data.pts < vo_pts + fast * ao_data.outburst/2 ? ao_data.outburst : 0; + else + return ao_data.buffersize; + + drain(); + return ao_data.buffersize - buffer; } // plays 'len' bytes of 'data' // it should round it down to outburst*n // return: number of bytes played static int play(void* data,int len,int flags){ + int maxbursts = (ao_data.buffersize - buffer) / ao_data.outburst; + int playbursts = len / ao_data.outburst; + int bursts = playbursts > maxbursts ? maxbursts : playbursts; + + if(fast) return len; - int maxbursts = (ao_data.buffersize - buffer) / ao_data.outburst; - int playbursts = len / ao_data.outburst; - int bursts = playbursts > maxbursts ? maxbursts : playbursts; - buffer += bursts * ao_data.outburst; - return bursts * ao_data.outburst; + buffer += bursts * ao_data.outburst; + return bursts * ao_data.outburst; } // return: delay in seconds between first and last sample in buffer static float get_delay(void){ + if(fast) return 0.0; - drain(); - return (float) buffer / (float) ao_data.bps; + drain(); + return (float) buffer / (float) ao_data.bps; } diff -ruNX mplayer-exclude mplayer-svn/libao2/ao_pcm.c mplayer-svn-monty/libao2/ao_pcm.c --- mplayer-svn/libao2/ao_pcm.c 2009-07-18 17:24:06.154908557 -0400 +++ mplayer-svn-monty/libao2/ao_pcm.c 2009-07-15 12:49:09.473247848 -0400 @@ -53,7 +53,8 @@ static char *ao_outputfilename = NULL; static int ao_pcm_waveheader = 1; -static int fast = 0; +static int localfast; +extern int fast; #define WAV_ID_RIFF 0x46464952 /* "RIFF" */ #define WAV_ID_WAVE 0x45564157 /* "WAVE" */ @@ -97,7 +98,7 @@ opt_t subopts[] = { {"waveheader", OPT_ARG_BOOL, &ao_pcm_waveheader, NULL}, {"file", OPT_ARG_MSTRZ, &ao_outputfilename, NULL}, - {"fast", OPT_ARG_BOOL, &fast, NULL}, + {"fast", OPT_ARG_BOOL, &localfast, NULL}, {NULL} }; // set defaults @@ -223,7 +224,7 @@ static int get_space(void){ if(vo_pts) - return ao_data.pts < vo_pts + fast * 30000 ? ao_data.outburst : 0; + return ao_data.pts < vo_pts + (fast|localfast) * 30000 ? ao_data.outburst : 0; return ao_data.outburst; } diff -ruNX mplayer-exclude mplayer-svn/libdvdread4/nav_read.c mplayer-svn-monty/libdvdread4/nav_read.c --- mplayer-svn/libdvdread4/nav_read.c 2009-07-06 04:05:05.161297261 -0400 +++ mplayer-svn-monty/libdvdread4/nav_read.c 2009-07-15 11:28:41.106191685 -0400 @@ -261,5 +261,5 @@ /* Asserts */ /* dsi dsi gi */ - CHECK_VALUE(dsi->dsi_gi.zero1 == 0); + //CHECK_VALUE(dsi->dsi_gi.zero1 == 0); } diff -ruNX mplayer-exclude mplayer-svn/libmpcodecs/dec_audio.c mplayer-svn-monty/libmpcodecs/dec_audio.c --- mplayer-svn/libmpcodecs/dec_audio.c 2009-07-18 17:23:52.161908379 -0400 +++ mplayer-svn-monty/libmpcodecs/dec_audio.c 2009-07-12 00:51:25.307150304 -0400 @@ -350,7 +350,7 @@ return 1; } -static int filter_n_bytes(sh_audio_t *sh, int len) +static int filter_n_bytes(sh_audio_t *sh, int len, double pts) { int error = 0; // Filter @@ -379,6 +379,7 @@ } filter_input.len = len; + filter_input.pts = pts; af_fix_parameters(&filter_input); filter_output = af_play(sh->afilter, &filter_input); if (!filter_output) @@ -407,7 +408,7 @@ * In the former case sh_audio->a_out_buffer_len is always >= minlen * on return. In case of EOF/error it might or might not be. * Can reallocate sh_audio->a_out_buffer if needed to fit all filter output. */ -int decode_audio(sh_audio_t *sh_audio, int minlen) +int decode_audio(sh_audio_t *sh_audio, int minlen, double pts) { // Indicates that a filter seems to be buffering large amounts of data int huge_filter_buffer = 0; @@ -447,7 +448,7 @@ /* if this iteration does not fill buffer, we must have lots * of buffering in filters */ huge_filter_buffer = 1; - if (filter_n_bytes(sh_audio, declen) < 0) + if (filter_n_bytes(sh_audio, declen, pts) < 0) return -1; } return 0; diff -ruNX mplayer-exclude mplayer-svn/libmpcodecs/dec_audio.h mplayer-svn-monty/libmpcodecs/dec_audio.h --- mplayer-svn/libmpcodecs/dec_audio.h 2009-07-18 17:23:52.162878457 -0400 +++ mplayer-svn-monty/libmpcodecs/dec_audio.h 2009-07-12 00:51:58.529213634 -0400 @@ -6,7 +6,7 @@ // dec_audio.c: void afm_help(void); int init_best_audio_codec(sh_audio_t *sh_audio, char** audio_codec_list, char** audio_fm_list); -int decode_audio(sh_audio_t *sh_audio, int minlen); +int decode_audio(sh_audio_t *sh_audio, int minlen, double pts); void resync_audio_stream(sh_audio_t *sh_audio); void skip_audio_frame(sh_audio_t *sh_audio); void uninit_audio(sh_audio_t *sh_audio); diff -ruNX mplayer-exclude mplayer-svn/libmpcodecs/vd_raw.c mplayer-svn-monty/libmpcodecs/vd_raw.c --- mplayer-svn/libmpcodecs/vd_raw.c 2009-07-18 17:23:52.150849555 -0400 +++ mplayer-svn-monty/libmpcodecs/vd_raw.c 2009-08-08 03:14:35.872709232 -0400 @@ -66,6 +66,10 @@ sh->disp_w, sh->disp_h); if(!mpi) return NULL; + // Passthrough; if a raw format is interlaced, the container had + // to have set it. Used by y4m and y4o. + mpi->fields = sh->fields; + if(mpi->flags&MP_IMGFLAG_PLANAR){ // TODO !!! mpi->planes[0]=data; diff -ruNX mplayer-exclude mplayer-svn/libmpcodecs/vd_theora.c mplayer-svn-monty/libmpcodecs/vd_theora.c --- mplayer-svn/libmpcodecs/vd_theora.c 2009-07-18 17:23:52.084893054 -0400 +++ mplayer-svn-monty/libmpcodecs/vd_theora.c 2009-08-13 03:37:22.744818572 -0400 @@ -20,27 +20,60 @@ LIBVD_EXTERN(theora) #include +#include #define THEORA_NUM_HEADER_PACKETS 3 -// to set/get/query special features/parameters -static int control(sh_video_t *sh,int cmd,void* arg,...){ - switch(cmd) { - case VDCTRL_QUERY_FORMAT: - if ((*((int*)arg)) == IMGFMT_YV12) - return CONTROL_TRUE; - return CONTROL_FALSE; - } - - return CONTROL_UNKNOWN; -} - typedef struct theora_struct_st { theora_state st; theora_comment cc; theora_info inf; } theora_struct_t; +#include "m_option.h" + +static int param_vismv=0; +static int param_vismbmode=0; +static int param_visqi=0; +static int param_visbits=0; +static int param_visall=0; + +m_option_t theora_decode_opts_conf[]={ + {"vismv", ¶m_vismv, CONF_TYPE_INT, CONF_RANGE, 0, 0xffff, NULL}, + {"vismbmode", ¶m_vismbmode, CONF_TYPE_INT, CONF_RANGE, 0, 0xffff, NULL}, + {"visqi", ¶m_visqi, CONF_TYPE_INT, CONF_RANGE, 0, 0xffff, NULL}, + {"visbits", ¶m_visbits, CONF_TYPE_INT, CONF_RANGE, 0, 0xffff, NULL}, + {"visall", ¶m_visall, CONF_TYPE_FLAG, 0, 0, 1, NULL}, + {NULL, NULL, 0, 0, 0, 0, NULL} +}; + +// to set/get/query special features/parameters +static int control(sh_video_t *sh,int cmd,void* arg,...){ + theora_struct_t *context; + context=sh->context; + + switch(cmd) { + case VDCTRL_QUERY_FORMAT: + switch(context->inf.pixelformat) { + case OC_PF_420: + if ((*((int*)arg)) == IMGFMT_YV12) + return CONTROL_TRUE; + break; + case OC_PF_422: + if ((*((int*)arg)) == IMGFMT_422P) + return CONTROL_TRUE; + break; + case OC_PF_444: + if ((*((int*)arg)) == IMGFMT_444P) + return CONTROL_TRUE; + break; + } + return CONTROL_FALSE; + } + + return CONTROL_UNKNOWN; +} + /* * init driver */ @@ -49,18 +82,9 @@ int failed = 1; int errorCode = 0; ogg_packet op; + int imgfmt; int i; - /* check whether video output format is supported */ - switch(sh->codec->outfmt[sh->outfmtidx]) - { - case IMGFMT_YV12: /* well, this should work... */ break; - default: - mp_msg (MSGT_DECVIDEO,MSGL_ERR,"Unsupported out_fmt: 0x%X\n", - sh->codec->outfmt[sh->outfmtidx]); - return 0; - } - /* this is not a loop, just a context, from which we can break on error */ do { @@ -89,11 +113,78 @@ /* now init codec */ errorCode = theora_decode_init (&context->st, &context->inf); if (errorCode) + { + mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Theora decode init failed: %i \n", + errorCode); + break; + } + + imgfmt=0; + switch(context->inf.pixelformat){ + case OC_PF_420:imgfmt=IMGFMT_YV12;break; + case OC_PF_422:imgfmt=IMGFMT_422P;break; + case OC_PF_444:imgfmt=IMGFMT_444P;break; + default: + { + mp_msg(MSGT_DECVIDEO,MSGL_ERR, + "Unknown Theora pixel format: %i \n", + context->inf.pixelformat); + } + } + if(imgfmt==0)break; + + if(param_visall){ + param_vismbmode=0xffff; + param_vismv=0xffff; + param_visqi=0xffff; + param_visbits=0xffff; + } + + if(param_vismbmode){ + errorCode = theora_control (&context->st, TH_DECCTL_SET_TELEMETRY_MBMODE, + ¶m_vismbmode,sizeof(param_vismbmode)); + if (errorCode) + mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Could not set macroblock visualization: %i \n", + errorCode); + } + + if(param_vismv){ + errorCode = theora_control (&context->st, TH_DECCTL_SET_TELEMETRY_MV, + ¶m_vismv,sizeof(param_vismv)); + if (errorCode) + mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Could not set motion vector visualization: %i \n", + errorCode); + } + + if(param_visqi){ + errorCode = theora_control (&context->st, TH_DECCTL_SET_TELEMETRY_QI, + ¶m_visqi,sizeof(param_visqi)); + if (errorCode) + mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Could not set quantizer visualization: %i \n", + errorCode); + } + + if(param_visbits){ + errorCode = theora_control (&context->st, TH_DECCTL_SET_TELEMETRY_BITS, + ¶m_visbits,sizeof(param_visbits)); + if (errorCode) + mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Could not set bit usage visualization: %i \n", + errorCode); + } + + /* set postprocessing if possible */ { - mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Theora decode init failed: %i \n", - errorCode); - break; + int pp_level_max; + errorCode = theora_control(&context->st, TH_DECCTL_GET_PPLEVEL_MAX,&pp_level_max, + sizeof(pp_level_max)); + if (!errorCode) + errorCode = theora_control(&context->st,TH_DECCTL_SET_PPLEVEL, + &pp_level_max,sizeof(pp_level_max)); + if (errorCode) + mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Could not enable Theora post-processing: %i \n", + errorCode); } + failed = 0; } while (0); @@ -115,7 +206,7 @@ mp_msg(MSGT_DECVIDEO,MSGL_V,"INFO: Theora video init ok!\n"); - return mpcodecs_config_vo (sh,context->inf.frame_width,context->inf.frame_height,IMGFMT_YV12); + return mpcodecs_config_vo (sh,context->inf.frame_width,context->inf.frame_height,imgfmt); } /* diff -ruNX mplayer-exclude mplayer-svn/libmpcodecs/vf.c mplayer-svn-monty/libmpcodecs/vf.c --- mplayer-svn/libmpcodecs/vf.c 2009-07-18 17:26:18.383908799 -0400 +++ mplayer-svn-monty/libmpcodecs/vf.c 2009-08-13 02:28:36.681767208 -0400 @@ -77,6 +77,7 @@ extern const vf_info_t vf_info_pullup; extern const vf_info_t vf_info_filmdint; extern const vf_info_t vf_info_framestep; +extern const vf_info_t vf_info_framemerge; extern const vf_info_t vf_info_tile; extern const vf_info_t vf_info_delogo; extern const vf_info_t vf_info_remove_logo; @@ -100,6 +101,8 @@ extern const vf_info_t vf_info_blackframe; extern const vf_info_t vf_info_geq; extern const vf_info_t vf_info_ow; +extern const vf_info_t vf_info_yuv4ogg; +extern const vf_info_t vf_info_nailfps; // list of available filters: static const vf_info_t* const filter_list[]={ @@ -168,6 +171,7 @@ &vf_info_pullup, &vf_info_filmdint, &vf_info_framestep, + &vf_info_framemerge, &vf_info_tile, &vf_info_delogo, &vf_info_remove_logo, @@ -193,6 +197,8 @@ &vf_info_yadif, &vf_info_blackframe, &vf_info_ow, + &vf_info_yuv4ogg, + &vf_info_nailfps, NULL }; @@ -269,7 +275,7 @@ if (w == -1) w = vf->w; if (h == -1) h = vf->h; - w2=(mp_imgflag&MP_IMGFLAG_ACCEPT_ALIGNED_STRIDE)?((w+15)&(~15)):w; + w2=((mp_imgflag&MP_IMGFLAG_ACCEPT_ALIGNED_STRIDE)?w:((w+15)&(~15))); if(vf->put_image==vf_next_put_image){ // passthru mode, if the filter uses the fallback/default put_image() code @@ -320,26 +326,10 @@ mpi->type=mp_imgtype; mpi->w=vf->w; mpi->h=vf->h; // keep buffer allocation status & color flags only: -// mpi->flags&=~(MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE|MP_IMGFLAG_DIRECT); mpi->flags&=MP_IMGFLAG_ALLOCATED|MP_IMGFLAG_TYPE_DISPLAYED|MP_IMGFLAGMASK_COLORS; // accept restrictions & draw_slice flags only: mpi->flags|=mp_imgflag&(MP_IMGFLAGMASK_RESTRICTIONS|MP_IMGFLAG_DRAW_CALLBACK); if(!vf->draw_slice) mpi->flags&=~MP_IMGFLAG_DRAW_CALLBACK; - if(mpi->width!=w2 || mpi->height!=h){ -// printf("vf.c: MPI parameters changed! %dx%d -> %dx%d \n", mpi->width,mpi->height,w2,h); - if(mpi->flags&MP_IMGFLAG_ALLOCATED){ - if(mpi->widthheightplanes[0]); - mpi->flags&=~MP_IMGFLAG_ALLOCATED; - mp_msg(MSGT_VFILTER,MSGL_V,"vf.c: have to REALLOCATE buffer memory :(\n"); - } -// } else { - } { - mpi->width=w2; mpi->chroma_width=(w2 + (1<chroma_x_shift) - 1)>>mpi->chroma_x_shift; - mpi->height=h; mpi->chroma_height=(h + (1<chroma_y_shift) - 1)>>mpi->chroma_y_shift; - } - } if(!mpi->bpp) mp_image_setfmt(mpi,outfmt); if(!(mpi->flags&MP_IMGFLAG_ALLOCATED) && mpi->type>MP_IMGTYPE_EXPORT){ @@ -642,6 +632,16 @@ vf->fmt.orig_height = height; vf->fmt.orig_width = width; vf->fmt.orig_fmt = outfmt; + + free_mp_image(vf->imgctx.static_images[0]); + free_mp_image(vf->imgctx.static_images[1]); + free_mp_image(vf->imgctx.temp_images[0]); + free_mp_image(vf->imgctx.export_images[0]); + vf->imgctx.static_images[0]=NULL; + vf->imgctx.static_images[1]=NULL; + vf->imgctx.temp_images[0]=NULL; + vf->imgctx.export_images[0]=NULL; + r = vf->config(vf, width, height, d_width, d_height, flags, outfmt); if (!r) vf->fmt.have_configured = 0; return r; diff -ruNX mplayer-exclude mplayer-svn/libmpcodecs/vf_framemerge.c mplayer-svn-monty/libmpcodecs/vf_framemerge.c --- mplayer-svn/libmpcodecs/vf_framemerge.c 1969-12-31 19:00:00.000000000 -0500 +++ mplayer-svn-monty/libmpcodecs/vf_framemerge.c 2009-07-13 07:53:21.872384561 -0400 @@ -0,0 +1,208 @@ +/* + * vf_fmerge.c - filter to ouput n merged frames as 1 frame + * + * The parameters are: + * + * num + * + */ + +#include +#include +#include + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" +#include "cpudetect.h" + +#include "img_format.h" +#include "mp_image.h" +#include "vf.h" + +#define MAXBUF 5 + +/* Private data */ +struct vf_priv_s { + /* Current frame */ + int frame_cur; + /* Frame output step, 0 = all */ + int frame_step; + + /* Buffered frames */ + int *planes[3]; + int width; + int height; + int n; +}; + +static void uninit_reinit(struct vf_instance_s* vf) +{ + if(vf && vf->priv){ + if(vf->priv->planes[0]) + free(vf->priv->planes[0]); + if(vf->priv->planes[1]) + free(vf->priv->planes[1]); + if(vf->priv->planes[2]) + free(vf->priv->planes[2]); + vf->priv->planes[0]=0; + vf->priv->planes[1]=0; + vf->priv->planes[2]=0; + } +} + +static void uninit(struct vf_instance_s* vf) +{ + uninit_reinit(vf); + /* Free private data */ + free(vf->priv); +} + +/* Filter handler */ +static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts) +{ + mp_image_t *dmpi; + struct vf_priv_s *priv; + int skip = 0; + + priv = vf->priv; + + if ((priv->frame_step != 0) && (((priv->frame_cur+1) % priv->frame_step) != 0)) { + skip = 1; + } + + /* Increment current frame */ + ++priv->frame_cur; + + if(priv->width != mpi->width || priv->height != mpi->height){ + uninit_reinit(vf); + } + + if(!priv->planes[0]){ + int width = priv->width = mpi->width; + int height = priv->height = mpi->height; + int p; + + for(p=0;p<3;p++){ + int is_chroma= !!p; + int w= width >>is_chroma; + int h= height>>is_chroma; + + priv->planes[p]=malloc(w*h*sizeof(int)); + } + priv->n=0; + } + + if (skip == 0) { + int p,x,y; + int width = priv->width; + int height = priv->height; + + /* Get image, export type (we don't modify tghe image) */ + dmpi=vf_get_image(vf->next, mpi->imgfmt, + MP_IMGTYPE_EXPORT, 0, + mpi->w, mpi->h); + /* Copy only the pointer ( MP_IMGTYPE_EXPORT ! ) */ + dmpi->planes[0] = mpi->planes[0]; + dmpi->planes[1] = mpi->planes[1]; + dmpi->planes[2] = mpi->planes[2]; + + dmpi->stride[0] = mpi->stride[0]; + dmpi->stride[1] = mpi->stride[1]; + dmpi->stride[2] = mpi->stride[2]; + + dmpi->width = mpi->width; + dmpi->height = mpi->height; + + if(priv->n){ + for(p=0;p<3;p++){ + int is_chroma= !!p; + int w= width >>is_chroma; + int h= height>>is_chroma; + unsigned char *dptr = dmpi->planes[p]; + int *sptr = priv->planes[p]; + float inv = 1./(priv->n+1); + + for(y=0;ystride[p]; + sptr+=w; + } + } + } + priv->n=0; + + /* Chain to next filter / output ... */ + return vf_next_put_image(vf, dmpi, pts); + }else{ + int p,x,y; + int width = priv->width; + int height = priv->height; + + for(p=0;p<3;p++){ + int is_chroma= !!p; + int w= width >>is_chroma; + int h= height>>is_chroma; + unsigned char *dptr = mpi->planes[p]; + int *sptr = priv->planes[p]; + + if(priv->n == 0){ + for(y=0;ystride[p]; + sptr+=w; + } + }else{ + for(y=0;ystride[p]; + sptr+=w; + } + } + } + priv->n++; + + } + + /* Skip the frame */ + return 0; +} + +/* Main entry funct for the filter */ +static int open(vf_instance_t *vf, char* args) +{ + struct vf_priv_s *p; + + vf->put_image = put_image; + vf->uninit = uninit; + vf->default_reqs = VFCAP_ACCEPT_STRIDE; + vf->priv = p = calloc(1, sizeof(struct vf_priv_s)); + if (p == NULL) { + return(0); + } + + if (args != NULL) { + if (*args != '\0') { + p->frame_step = atoi(args); + if (p->frame_step <= 0) { + mp_msg(MSGT_VFILTER, MSGL_WARN, MSGTR_MPCODECS_ErrorParsingArgument); + return(0); + } + } + } + return 1; +} + +const vf_info_t vf_info_framemerge = { + "Merge every n frames", + "framemerge", + "Monty", + "", + open, + NULL +}; + + diff -ruNX mplayer-exclude mplayer-svn/libmpcodecs/vf_nailfps.c mplayer-svn-monty/libmpcodecs/vf_nailfps.c --- mplayer-svn/libmpcodecs/vf_nailfps.c 1969-12-31 19:00:00.000000000 -0500 +++ mplayer-svn-monty/libmpcodecs/vf_nailfps.c 2009-08-13 02:40:45.989740746 -0400 @@ -0,0 +1,200 @@ +/* + * + * vf_nailfps, part of MPlayer + * + * Copyright (C) 2007 Monty + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Postfish; see the file COPYING. If not, write to the + * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +/* nailfps creates a fixed-frame-rate output, much like -ofps for mencoder. */ + +#include +#include +#include + +#include "config.h" +#include "mp_msg.h" + +#include "img_format.h" +#include "mp_image.h" +#include "vf.h" + +// static vars, not a priv struct, because the state must be preserved +// across multiple opens ala -fixed-vo. Only one nailfps filter is +// possible at a time but only one makes sense. + +extern int correct_pts; +extern double force_fps; + +int vf_nailfps_active=0; +double vf_nailfps_offset=0; +double vf_last_pts=0; + +int resync_count=0; +int resync_frames=30; + +static int drop_last=0; +static int add_last=0; +static long vf_nailfps_frame=-1; +static mp_image_t *buffered_mpi=NULL; +static double hyst=.25; + +static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts){ + double pos = pts*force_fps; + mp_image_t *dmpi; + int ret=0; + int flag = 1; + int loop = 0; + double dhyst = hyst+.5; + double ahyst = hyst+.5; + + if(!mpi) return 0; // bulletproofing + + if(vf_nailfps_frame == -1){ + vf_nailfps_frame=0; + vf_last_pts=vf_nailfps_offset = pts; + drop_last=0; + add_last=0; + } + + //mp_msg(MSGT_VFILTER, MSGL_INFO, + // "\n[nailfps] video pts is %.3f, offset is %.3f\n",pts,vf_nailfps_offset); + + pos-=vf_nailfps_offset*force_fps; + + vf_last_pts = pts; + + while(flag){ + if(drop_last)dhyst=0; + if(add_last)ahyst=0; + drop_last=0; + add_last=0; + flag=0; + loop++; + + if(posvf_nailfps_frame+ahyst){ + mp_msg(MSGT_VFILTER, MSGL_INFO, + "\n[nailfps] adding frame at position %ld (clock V: %.3f, input V: %.3f)\n", + vf_nailfps_frame,vf_nailfps_frame/force_fps+vf_nailfps_offset, pts); + flag=1; + add_last=1; + } + + if(flag && buffered_mpi){ + // we want to maintain the last frame (if it exists) across the gap, not start the new frame early. + dmpi=vf_get_image(vf->next, buffered_mpi->imgfmt, + MP_IMGTYPE_EXPORT, 0, + buffered_mpi->w, buffered_mpi->h); + + dmpi->planes[0] = buffered_mpi->planes[0]; + dmpi->planes[1] = buffered_mpi->planes[1]; + dmpi->planes[2] = buffered_mpi->planes[2]; + dmpi->stride[0] = buffered_mpi->stride[0]; + dmpi->stride[1] = buffered_mpi->stride[1]; + dmpi->stride[2] = buffered_mpi->stride[2]; + }else{ + // current frame, or no previous frame to fill a gap + dmpi=vf_get_image(vf->next, mpi->imgfmt, + MP_IMGTYPE_EXPORT, 0, + mpi->w, mpi->h); + + dmpi->planes[0] = mpi->planes[0]; + dmpi->planes[1] = mpi->planes[1]; + dmpi->planes[2] = mpi->planes[2]; + dmpi->stride[0] = mpi->stride[0]; + dmpi->stride[1] = mpi->stride[1]; + dmpi->stride[2] = mpi->stride[2]; + } + + ret |= vf_next_put_image(vf, dmpi, vf_nailfps_frame/(double)force_fps+vf_nailfps_offset); + ++vf_nailfps_frame; + + // we always do this the 'old' (non correct-pts) way because + // the extra frame generation confuses the Hell out of + // correct-pts's sync algorithm after seeks. We bang the + // frames directly and correct-pts is none the wiser, + // preventing huge sync offsets in playback that take + // forever to settle out. + if (flag) + vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL); + } + + // save this frame in case we hit a gap + buffered_mpi = mpi; + return ret; +} + +static int query_format(struct vf_instance_s* vf, unsigned int fmt){ + return vf_next_query_format(vf, fmt); +} + +static void uninit(struct vf_instance_s* vf){ + vf_nailfps_active = 0; + vf_nailfps_frame=-1; + buffered_mpi = NULL; +} + +static int open(vf_instance_t *vf, char* args){ + if(vf_nailfps_active){ + mp_msg(MSGT_VFILTER, MSGL_FATAL, + "\n[nailfps] only one nailfps instance allowed.\n"); + return 0; + } + + if(force_fps<=0){ + mp_msg(MSGT_VFILTER, MSGL_FATAL, + "\n[nailfps] -fps option required when using -vf nailfps.\n"); + return 0; + } + + vf->query_format=query_format; + vf->put_image=put_image; + vf->uninit=uninit; + vf_nailfps_active = 1; + + if (args) sscanf(args, "%lf:%d", &hyst,&resync_frames); + if(hyst<0. || hyst>2.){ + mp_msg(MSGT_VFILTER, MSGL_FATAL, + "\n[nailfps] Hysteresis option must be in the range 0. <= n <=2., default is .2\n"); + return 0; + } + if(resync_frames<0 || resync_frames>120){ + mp_msg(MSGT_VFILTER, MSGL_FATAL, + "\n[nailfps] Resync option must be in the range 0 <= n <= 120, default is 30\n"); + return 0; + } + + return 1; +} + +vf_info_t vf_info_nailfps = { + "nail physical framerate to -fps", + "nailfps", + "Monty", + "", + open, + NULL +}; diff -ruNX mplayer-exclude mplayer-svn/libmpcodecs/vf_tfields.c mplayer-svn-monty/libmpcodecs/vf_tfields.c --- mplayer-svn/libmpcodecs/vf_tfields.c 2009-07-18 17:23:52.124913576 -0400 +++ mplayer-svn-monty/libmpcodecs/vf_tfields.c 2009-08-10 16:23:07.576743014 -0400 @@ -361,11 +361,15 @@ dmpi->stride[1] = 2*mpi->stride[1]; dmpi->stride[2] = 2*mpi->stride[2]; } - ret |= vf_next_put_image(vf, dmpi, pts); + dmpi->fields=0; + ret = vf_next_put_image(vf, dmpi, pts); if (correct_pts) break; else - if (!i) vf_extra_flip(vf); + if (!i && ret){ + vf_extra_flip(vf); + ret=0; + } } break; case 1: @@ -391,11 +395,15 @@ deint(dmpi->planes[2], dmpi->stride[2], mpi->planes[2], mpi->stride[2], mpi->chroma_width, mpi->chroma_height, (i^!tff)); } - ret |= vf_next_put_image(vf, dmpi, pts); + dmpi->fields=0; + ret = vf_next_put_image(vf, dmpi, pts); if (correct_pts) break; else - if (!i) vf_extra_flip(vf); + if (!i && ret){ + vf_extra_flip(vf); + ret=0; + } } break; case 2: @@ -417,11 +425,15 @@ mpi->chroma_width, mpi->chroma_height/2, dmpi->stride[2], mpi->stride[2]*2, (i^!tff)); } - ret |= vf_next_put_image(vf, dmpi, pts); + dmpi->fields=0; + ret = vf_next_put_image(vf, dmpi, pts); if (correct_pts) break; else - if (!i) vf_extra_flip(vf); + if (!i && ret){ + vf_extra_flip(vf); + ret=0; + } } break; } diff -ruNX mplayer-exclude mplayer-svn/libmpcodecs/vf_yadif.c mplayer-svn-monty/libmpcodecs/vf_yadif.c --- mplayer-svn/libmpcodecs/vf_yadif.c 2009-07-18 17:23:52.163912722 -0400 +++ mplayer-svn-monty/libmpcodecs/vf_yadif.c 2009-08-10 16:21:18.502692815 -0400 @@ -429,13 +429,16 @@ mpi->width,mpi->height); vf_clone_mpi_attributes(dmpi, mpi); filter(vf->priv, dmpi->planes, dmpi->stride, mpi->w, mpi->h, i ^ tff ^ 1, tff); + dmpi->fields = 0; if (correct_pts && i < (vf->priv->mode & 1)) vf_queue_frame(vf, continue_buffered_image); - ret |= vf_next_put_image(vf, dmpi, pts /*FIXME*/); + ret = vf_next_put_image(vf, dmpi, pts /*FIXME*/); if (correct_pts) break; - if(i<(vf->priv->mode&1)) + if(i<(vf->priv->mode&1) && ret){ vf_extra_flip(vf); + ret=0; + } } vf->priv->buffered_i = 1; return ret; diff -ruNX mplayer-exclude mplayer-svn/libmpcodecs/vf_yuv4ogg.c mplayer-svn-monty/libmpcodecs/vf_yuv4ogg.c --- mplayer-svn/libmpcodecs/vf_yuv4ogg.c 1969-12-31 19:00:00.000000000 -0500 +++ mplayer-svn-monty/libmpcodecs/vf_yuv4ogg.c 2009-08-10 03:31:38.901670177 -0400 @@ -0,0 +1,601 @@ +/* + * yuv4ogg (yuv4oggtools) interface + * + * Output video, as it passes through, to a yuv4ogg + * output file. Can cooperate with af_yuv4ogg.c to form a single + * timed/interleaved output pipe to send to external utils, such as + * yuv4oggtool. + * + * This output is implemented as a filter, not a vo, so that mplayer + * can simultaneously output to external utilities while being used as + * a 'preview' display. + * + * Parameters: + * + * [outputfile] (usually a named pipe). default will be to use last + * filename passed to a yuv4ogg filter or 'output.y4o' if none has yet + * been specified. +*/ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#include "img_format.h" +#include "mp_image.h" +#include "vf.h" +#include "libvo/video_out.h" +#include "vf_yuv4ogg.h" + +/* the cross-plugin state for the various y4o filters is here */ + +static struct y4o_file_entry *entry_list=NULL; +static char *last_filename=NULL; + +struct y4o_file_entry *y4o_fetch_entry(char *filename){ + struct y4o_file_entry *last=NULL; + struct y4o_file_entry *ep=entry_list; + + if(filename == NULL) + filename=last_filename; + if(filename == NULL) + filename="output.y4o"; + last_filename = filename; + + while(ep){ + if(!strcmp(ep->filename,filename)) break; + last=ep; + ep=ep->next; + } + + if(ep==NULL){ + FILE *f; + + /* allocate a new entry, start a new stream */ + + mp_msg(MSGT_VFILTER, MSGL_INFO, + "[yuv4ogg] allocating new stream entry for %s\n",filename); + + f = fopen(filename,"wb"); + if(!f){ + mp_msg(MSGT_VFILTER, MSGL_FATAL, + "[yuv4ogg] Unable to open %s: %s\n", + filename, strerror(errno)); + exit(1); + } + ep = calloc(1,sizeof(*ep)); + if(ep==NULL){ + mp_msg(MSGT_VFILTER, MSGL_FATAL, + "[yuv4ogg] Unable to allocate stream entry struct\n"); + exit(1); + } + + if(last==NULL){ + entry_list = ep; + }else{ + last->next=ep; + } + + ep->filename = strdup(filename); + ep->fd = f; + }else + mp_msg(MSGT_VFILTER, MSGL_INFO, + "[yuv4ogg] reusing stream entry for %s\n",ep->filename); + ep->stream_counter++; + + return ep; +} + +int y4o_start(struct y4o_file_entry *e){ + if(!e->started){ + /* can we start? Ask the plugins */ + int startflag=1; + struct y4o_callback_entry *p = e->stream; + while(p){ + if(!p->ready(p->priv)){ + startflag=0; + break; + } + p=p->next; + } + if(!startflag)return 0; + + /* we can start! Write our header */ + fprintf(e->fd,"YUV4OGG Sn\n"); /* unsynced yuv4ogg */ + + /* streams are in reverse order; turn list around */ + p=e->stream; + e->stream=NULL; + while(p){ + struct y4o_callback_entry *next=p->next; + p->next=e->stream; + e->stream=p; + p=next; + } + + /* have the streams write their headers */ + p = e->stream; + while(p){ + p->start(p->priv); + p=p->next; + } + e->started=1; + } + return 1; +} + +void y4o_restart(){ + struct y4o_file_entry *ep=entry_list; + last_filename=NULL; + + /* mark file entries for restart */ + while(ep){ + ep->stream_counter=0; + ep=ep->next; + } +} + +void y4o_exit(){ + while(entry_list){ + struct y4o_file_entry *ep=entry_list; + entry_list=ep->next; + + while(ep->stream){ + struct y4o_callback_entry *c=ep->stream; + c->exit(c->priv); + ep->stream = c->next; + free(c); + } + + fflush(ep->fd); + fclose(ep->fd); + free(ep->filename); + free(ep); + } +} + +/* Private data for vf_yuv4ogg */ + +/* buffering in the event we need to swallow frames before another y4o + plugin is ready to write a header */ +struct mpi_buffer { + mp_image_t *mpi; + double pts; + struct mpi_buffer *next; +}; + +typedef enum { + Cmono=0, + C411ntscdv=1, + C420jpeg=2, + C420mpeg2=3, + C420paldv=4, + C420unknown=5, + C422jpeg=6, + C422smpte=7, + C422unknown=8, + C444=9, +} chromafmt; + +static char *chromaformat[10]={ + "mono", //0 + "411ntscdv", //1 + "420jpeg", //2 chroma sample is centered vertically and horizontally between luma samples + "420mpeg2", //3 chroma sample is centered vertically between lines, cosited horizontally */ + "420paldv", //4 chroma sample is cosited vertically and horizontally */ + "420unknown",//5 + "422jpeg", //6 chroma sample is horizontally centered between luma samples */ + "422smpte", //7 chroma sample is cosited horizontally */ + "422unknown",//8 + "444", //9 +}; + +struct vf_priv_s { + struct y4o_file_entry *entry; + int stream_num; + + struct mpi_buffer *buffer; + + int can_start; + int w; + int h; + int d_w; + int d_h; + int interlace; + int fps_num; + int fps_den; + int pa_num; + int pa_den; + unsigned int fmt; + chromafmt c; +}; + +static int vf_y4o_ready(struct vf_priv_s *p){ + return p->can_start; +} + +static void vf_y4o_start(struct vf_priv_s *p){ + fprintf(p->entry->fd,"VIDEO W%d H%d F%d:%d I%c A%d:%d C%s\n", + p->w, p->h, p->fps_num, p->fps_den, (p->interlace?(p->interlace==1?'t':'b'):'p'), + p->pa_num, p->pa_den, chromaformat[p->c]); +} + +static void vf_y4o_exit(struct vf_priv_s *p){ + struct mpi_buffer *b=p->buffer; + while(b){ + struct mpi_buffer *next=b->next; + free_mp_image(b->mpi); + free(b); + b=next; + } + free(p); +} + +static int abort_put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts); + +static void vf_y4o_write(struct vf_instance_s *vf, const void *ptr, const size_t num_bytes) +{ + if (fwrite(ptr, 1, num_bytes, vf->priv->entry->fd) != num_bytes){ + mp_msg(MSGT_VFILTER,MSGL_ERR,"\n[yuv4ogg] Write error: %s\n",strerror(errno)); + mp_msg(MSGT_VFILTER,MSGL_ERR," Aborting stream\n"); + vf->put_image=abort_put_image; + } +} + +static void vf_y4o_write_frame(struct vf_instance_s *vf, mp_image_t *mpi, double pts){ + int y; + + if(mpi->w != vf->priv->w || + mpi->h != vf->priv->h || + mpi->imgfmt != vf->priv->fmt){ + + mp_msg(MSGT_VFILTER,MSGL_ERR,"\n[yuv4ogg] ERROR: Video dimensions/format changed for %s stream %d\n", + vf->priv->entry->filename,vf->priv->stream_num); + mp_msg(MSGT_VFILTER,MSGL_ERR," Aborting stream\n"); + vf->put_image=abort_put_image; + return; + } + + /* vo_yuv4mpeg states: + + "When processing interlaced material we want to get the raw RGB + data and do the YV12 conversion ourselves to have the chrominance + information sampled correct." + + ....and then proceeds to output exactly the same thing as YV12 + marked it C420jpeg (wrong). + + We ouput the interlaced chroma as it arrives and mark the + positioning 'unknown' because theres no way to tell within + mplayer what subsample positioning its actually using (mplayer + itself doesn't know and ignores the whole issue). */ + { + int cw=mpi->chroma_width; + int ch=mpi->chroma_height; + int cx=mpi->x>>mpi->chroma_x_shift; + int cy=mpi->y>>mpi->chroma_y_shift; + int bytes = vf->priv->w*vf->priv->h + cw*ch*2; + unsigned char *src; + int up=1, vp=2; + + fprintf(vf->priv->entry->fd,"FRAME S%d L%d P%.3f\n",vf->priv->stream_num,bytes,pts); + + /* in all cases, full sized Y comes first */ + src = mpi->planes[0]+(mpi->y*mpi->stride[0])+mpi->x; + for(y=0;yh;y++){ + vf_y4o_write(vf,src,vf->priv->w); + src+=mpi->stride[0]; + } + + /* If we're not mono, some size of U comes next... */ + src = mpi->planes[up]+(cy*mpi->stride[up])+cx; + for(y=0;ystride[up]; + } + + /* write V */ + src = mpi->planes[vp]+(cy*mpi->stride[vp])+cx; + for(y=0;ystride[vp]; + } + } +} + +/* Filter handler */ +#define EPSILON 1e-6 +static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts) +{ + mp_image_t *dmpi; + struct vf_priv_s *p = vf->priv; + + if(!p->can_start){ + /* our first frame, the first chance to see some config like interlace */ + p->w = mpi->w; + p->h = mpi->h; + + if(mpi->fields & MP_IMGFIELD_INTERLACED){ + if (mpi->fields & MP_IMGFIELD_ORDERED) + p->interlace = 2-!!(mpi->fields & MP_IMGFIELD_TOP_FIRST); + else + p->interlace = 1; + }else + p->interlace = 0; + + { + int d; + if(fabs(rint(vo_fps*1001) - vo_fps*1001)fps_num = rint(vo_fps*d); + p->fps_den = d; + } + + { + int d; + int best=-1; + double besterr=0; + double pa = (p->d_w/(double)p->d_h) / (p->w/(double)p->h); + for(d=1;d<1000;d++){ + double err=fabs(rint(pa*d) - pa*d); + if(best == -1 || errpa_num = rint(pa*best); + p->pa_den = best; + } + + p->can_start=1; + } + + if(!y4o_start(p->entry)){ + /* another plugin is not ready to write its header... no choice + but to buffer this frame */ + + struct mpi_buffer *b = calloc(1,sizeof(*b)); + mp_image_t *bmpi = alloc_mpi(mpi->w,mpi->h,mpi->imgfmt); + + mp_msg(MSGT_VFILTER, MSGL_INFO, + "\n[yuv4ogg] Stream %d buffering frame while waiting for other streams...\n", p->stream_num); + + if(!b || !bmpi){ + if(b)free(b); + if(bmpi)free_mp_image(bmpi); + mp_msg(MSGT_VFILTER, MSGL_FATAL, + "\n[yuv4ogg] failed to buffer frame while waiting for initialization!\n"); + }else{ + copy_mpi(bmpi,mpi); + b->mpi=bmpi; + b->pts = pts; + b->next = p->buffer; + p->buffer = b; + } + }else{ + /* write any buffered frames */ + if(p->buffer){ + struct mpi_buffer *b=p->buffer; + mp_msg(MSGT_AFILTER, MSGL_INFO, + "\n[yuv4ogg] Stream %d done waiting, writing buffered frames...\n",p->stream_num); + p->buffer=NULL; + while(b){ + struct mpi_buffer *next=b->next; + b->next=p->buffer; + p->buffer=b; + b=next; + } + + b=p->buffer; + p->buffer=NULL; + while(b){ + struct mpi_buffer *next=b->next; + vf_y4o_write_frame(vf,b->mpi,b->pts); + free_mp_image(b->mpi); + free(b); + b=next; + } + } + /* write this frame */ + vf_y4o_write_frame(vf,mpi,pts); + } + + /* Get image, export type (we don't modify the image) */ + dmpi=vf_get_image(vf->next, mpi->imgfmt, + MP_IMGTYPE_EXPORT, 0, + mpi->w, mpi->h); + + dmpi->planes[0] = mpi->planes[0]; + dmpi->planes[1] = mpi->planes[1]; + dmpi->planes[2] = mpi->planes[2]; + + dmpi->stride[0] = mpi->stride[0]; + dmpi->stride[1] = mpi->stride[1]; + dmpi->stride[2] = mpi->stride[2]; + + dmpi->width = mpi->width; + dmpi->height = mpi->height; + + /* Chain to next filter / output ... */ + return vf_next_put_image(vf, dmpi, pts); +} + +static int abort_put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts) +{ + mp_image_t *dmpi; + + /* Get image, export type (we don't modify the image) */ + dmpi=vf_get_image(vf->next, mpi->imgfmt, + MP_IMGTYPE_EXPORT, 0, + mpi->w, mpi->h); + + dmpi->planes[0] = mpi->planes[0]; + dmpi->planes[1] = mpi->planes[1]; + dmpi->planes[2] = mpi->planes[2]; + + dmpi->stride[0] = mpi->stride[0]; + dmpi->stride[1] = mpi->stride[1]; + dmpi->stride[2] = mpi->stride[2]; + + dmpi->width = mpi->width; + dmpi->height = mpi->height; + + /* Chain to next filter / output ... */ + return vf_next_put_image(vf, dmpi, pts); +} + +static int query_format(struct vf_instance_s* vf, unsigned int fmt) +{ + + /* the software scaler in mplayer is seriously problematic-- it does + not seem to realize there are multiple chroma positionings + possible and appears to always blindly use MPEG2 positioning. + Unfortunately, theora requires JPEG/MPEG1 style chroma. In + addition, the YUV4MPEG vo also blasts out YV12 (MPEG2 + positioning) but declares the positioning to MPEG1/JPEG. Is + *anything* in this damned software package written correctly? */ + + /* accept all these samplings, but always output the chroma + subsample positioning as 'unknown' */ + + vf->priv->fmt=fmt; + + switch(fmt){ + case IMGFMT_Y8: + case IMGFMT_Y800: + vf->priv->c = Cmono; + return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW; + + case IMGFMT_YV12: + case IMGFMT_I420: + case IMGFMT_IYUV: + vf->priv->c = C420unknown; + return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW; + + // For now, disabled as we generally always want 4:2:0 and mplayer + // randomply ends up using 4:4:4 at various pipeline stages. + // case IMGFMT_422P: + //vf->priv->c = C422unknown; + //return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW; + + //case IMGFMT_444P: + //vf->priv->c = C444; + //return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW; + } + + return 0; +} + +static int config(struct vf_instance_s* vf, + int width, int height, int d_width, int d_height, + unsigned int flags, unsigned int outfmt){ + + if(!vf->priv->entry->started){ + vf->priv->d_w = d_width; + vf->priv->d_h = d_height; + } + + return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); +} + +static void uninit(struct vf_instance_s* vf) +{ + mp_msg(MSGT_VFILTER, MSGL_INFO, + "[yuv4ogg] suspending %s stream %d\n",vf->priv->entry->filename,vf->priv->stream_num); + + /* mark file entry for restart */ + y4o_restart(); +} + +/* Main entry funct for the filter */ +static int open(vf_instance_t *vf, char* args) +{ + char *filename=NULL; + struct vf_priv_s *p; + struct y4o_callback_entry *c; + struct y4o_file_entry *entry; + + mp_msg(MSGT_VFILTER, MSGL_INFO, + "[yuv4ogg] opening with args %s\n",args?args:"(none)"); + entry = y4o_fetch_entry(args); + + if(entry->started){ + /* reinitialization case */ + int i,stream_num = entry->stream_counter-1; + c = entry->stream; + for(i=0;inext; + if(!c){ + mp_msg(MSGT_VFILTER, MSGL_FATAL, + "[yuv4ogg] unable to add new stream to file %s after playback started\n",entry->filename); + return 0; + } + vf->priv = c->priv; + mp_msg(MSGT_VFILTER, MSGL_INFO, + "[yuv4ogg] restarting as %s stream %d\n",entry->filename,stream_num); + + }else{ + c=calloc(1,sizeof(*c)); + if(!c){ + mp_msg(MSGT_VFILTER, MSGL_FATAL, + "[yuv4ogg] unable to allocate callback struct\n"); + return 0; + } + + vf->priv = p = calloc(1, sizeof(*p)); + if (p == NULL) { + return 0; + } + + if (args != NULL) + if (*args != '\0') + filename=args; + + p->entry=entry; + p->stream_num = p->entry->stream_counter-1; + c->ready = (int (*)(void *))vf_y4o_ready; + c->start = (void (*)(void *))vf_y4o_start; + c->exit = (void (*)(void *))vf_y4o_exit; + c->priv = p; + c->next = entry->stream; + entry->stream=c; + + mp_msg(MSGT_VFILTER, MSGL_INFO, + "[yuv4ogg] starting as %s stream %d\n",entry->filename,p->stream_num); + + } + + vf->put_image = put_image; + vf->uninit = uninit; + vf->config = config; + vf->query_format = query_format; + vf->default_reqs = VFCAP_ACCEPT_STRIDE; + + return 1; +} + +const vf_info_t vf_info_yuv4ogg = { + "Output video frames to yuv4ogg", + "yuv4ogg", + "Monty", + "", + open, + NULL +}; + + diff -ruNX mplayer-exclude mplayer-svn/libmpcodecs/vf_yuv4ogg.h mplayer-svn-monty/libmpcodecs/vf_yuv4ogg.h --- mplayer-svn/libmpcodecs/vf_yuv4ogg.h 1969-12-31 19:00:00.000000000 -0500 +++ mplayer-svn-monty/libmpcodecs/vf_yuv4ogg.h 2009-07-15 05:56:08.666239997 -0400 @@ -0,0 +1,27 @@ +/* + * yuv4ogg (yuv4oggtools) interface + * + * Common shared type state between vf and af y4o filters +*/ + +struct y4o_callback_entry { + void *priv; + int (*ready)(void *priv); + void (*start)(void *priv); + void (*exit)(void *priv); + struct y4o_callback_entry *next; +}; + +struct y4o_file_entry { + char *filename; + FILE *fd; + int started; + int stream_counter; /* tracks streams as they start / go through reinit */ + struct y4o_callback_entry *stream; + struct y4o_file_entry *next; +}; + +extern struct y4o_file_entry *y4o_fetch_entry(char *filename); +extern int y4o_start(struct y4o_file_entry *e); +extern void y4o_restart(); +extern void y4o_exit(); diff -ruNX mplayer-exclude mplayer-svn/libmpdemux/demuxer.c mplayer-svn-monty/libmpdemux/demuxer.c --- mplayer-svn/libmpdemux/demuxer.c 2009-07-18 17:24:35.932902896 -0400 +++ mplayer-svn-monty/libmpdemux/demuxer.c 2009-07-14 07:55:58.000000000 -0400 @@ -62,6 +62,7 @@ extern const demuxer_desc_t demuxer_desc_mf; extern const demuxer_desc_t demuxer_desc_avi; extern const demuxer_desc_t demuxer_desc_y4m; +extern const demuxer_desc_t demuxer_desc_y4o; extern const demuxer_desc_t demuxer_desc_asf; extern const demuxer_desc_t demuxer_desc_real; extern const demuxer_desc_t demuxer_desc_smjpeg; @@ -115,6 +116,7 @@ #endif &demuxer_desc_avi, &demuxer_desc_y4m, + &demuxer_desc_y4o, &demuxer_desc_asf, &demuxer_desc_nsv, &demuxer_desc_real, diff -ruNX mplayer-exclude mplayer-svn/libmpdemux/demuxer.h mplayer-svn-monty/libmpdemux/demuxer.h --- mplayer-svn/libmpdemux/demuxer.h 2009-07-18 17:24:35.933908908 -0400 +++ mplayer-svn-monty/libmpdemux/demuxer.h 2009-07-14 08:01:33.000000000 -0400 @@ -53,6 +53,7 @@ #define DEMUXER_TYPE_FLI 10 #define DEMUXER_TYPE_REAL 11 #define DEMUXER_TYPE_Y4M 12 +#define DEMUXER_TYPE_Y4O 13 #define DEMUXER_TYPE_FILM 14 #define DEMUXER_TYPE_ROQ 15 #define DEMUXER_TYPE_MF 16 diff -ruNX mplayer-exclude mplayer-svn/libmpdemux/demux_y4m.c mplayer-svn-monty/libmpdemux/demux_y4m.c --- mplayer-svn/libmpdemux/demux_y4m.c 2009-07-18 17:24:35.882913684 -0400 +++ mplayer-svn-monty/libmpdemux/demux_y4m.c 2009-07-14 15:21:07.944241717 -0400 @@ -35,6 +35,7 @@ //#include "stream/stream.h" #include "demuxer.h" #include "stheader.h" +#include "libmpcodecs/mp_image.h" typedef struct { int framenum; @@ -139,6 +140,7 @@ static demuxer_t* demux_open_y4m(demuxer_t* demuxer){ y4m_priv_t* priv = demuxer->priv; y4m_ratio_t ratio; + int interlace; sh_video_t* sh=new_sh_video(demuxer,0); int err; @@ -223,6 +225,19 @@ if (ratio.d != 0 && ratio.n != 0) sh->aspect = (float)(sh->disp_w*ratio.n)/(float)(sh->disp_h*ratio.d); + interlace = y4m_si_get_interlace(priv->si); + switch(interlace){ + case Y4M_ILACE_TOP_FIRST: + sh->fields = MP_IMGFIELD_ORDERED|MP_IMGFIELD_TOP_FIRST|MP_IMGFIELD_INTERLACED; + break; + case Y4M_ILACE_BOTTOM_FIRST: + sh->fields = MP_IMGFIELD_ORDERED|MP_IMGFIELD_INTERLACED; + break; + default: + sh->fields=0; + break; + } + demuxer->seekable = 0; } diff -ruNX mplayer-exclude mplayer-svn/libmpdemux/demux_y4o.c mplayer-svn-monty/libmpdemux/demux_y4o.c --- mplayer-svn/libmpdemux/demux_y4o.c 1969-12-31 19:00:00.000000000 -0500 +++ mplayer-svn-monty/libmpdemux/demux_y4o.c 2009-08-08 03:00:54.171690240 -0400 @@ -0,0 +1,848 @@ +/* + * Y4O file parser + * copyright (c) 2009 Monty, based on Y4M parser (c) 2001 Rik Snel + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include /* strtok */ + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" +#include "demuxer.h" +#include "stheader.h" +#include "libmpcodecs/mp_image.h" +#include "libaf/af_format.h" + +#define MAX_STREAMS 255 +typedef struct { + int streams; + int bytespersec; +} y4o_priv_t; + +typedef enum { + Cmono=0, + C411ntscdv=1, + C420jpeg=2, + C420mpeg2=3, + C420paldv=4, + C420unknown=5, + C422jpeg=6, + C422smpte=7, + C422unknown=8, + C444=9, +} chromafmt; + +static char *chromaformat[]={ + "mono", //0 + "411ntscdv", //1 + "420jpeg", //2 chroma sample is centered vertically and horizontally between luma samples + "420mpeg2", //3 chroma sample is centered vertically between lines, cosited horizontally */ + "420paldv", //4 chroma sample is cosited vertically and horizontally */ + "420unknown",//5 + "422jpeg", //6 chroma sample is horizontally centered between luma samples */ + "422smpte", //7 chroma sample is cosited horizontally */ + "422unknown",//8 + "444", //9 + NULL +}; + +static int demux_y4o_id(demuxer_t* demuxer){ + int orig_pos = stream_tell(demuxer->stream); + char buf[8]; + + demuxer->priv = NULL; // we don't need it + + mp_msg(MSGT_DEMUX, MSGL_V, "Checking for YUV4OGG\n"); + + if(stream_read(demuxer->stream, buf, 7)!=7) + return 0; + + buf[7] = 0; + + if (strncmp("YUV4OGG", buf, 7)) + return 0; + + mp_msg(MSGT_DEMUX,MSGL_DBG2,"Success: YUV4OGG\n"); + + stream_seek(demuxer->stream, orig_pos); + + return DEMUXER_TYPE_Y4O; +} + +ssize_t read_wrap(stream_t *s, char *buf, size_t len) +{ + ssize_t n; + + while (len > 0) { + n = stream_read(s, buf, len); + if (n <= 0) { + /* return amount left to read */ + if (n == 0){ + return len; /* n == 0 --> eof */ + }else{ + mp_msg(MSGT_DEMUX, MSGL_V, "[yuv4ogg] ERROR: stream read failed\n"); + return -len; /* n < 0 --> error */ + } + } + buf += n; + len -= n; + } + return 0; +} + +static int y4o_read_container_header(stream_t *s, int *sync){ + char line[80]; + char *p; + int n,err; + ssize_t remain; + + remain = read_wrap(s, line, sizeof("YUV4OGG")); + if (remain){ + if( remain > 0) + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: EOF reading file header\n"); + return 1; + } + + if (strncmp(line, "YUV4OGG ", sizeof("YUV4OGG ")-1)){ + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: cannot parse file header\n"); + return 1; + } + + /* proceed to get the tags... (overwrite the magic) */ + for (n = 0, p = line; n < 80; n++, p++) { + if ((err=read_wrap(s, p, 1))){ + if(err>0) + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: EOF reading file header\n"); + return 1; + } + if (*p == '\n') { + *p = '\0'; + break; + } + } + if (n >= 80) { + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: line too long reading file header\n"); + return 1; + } + + /* read tags */ + /* S%c = sync */ + + { + char *token, *value; + char tag; + + *sync=-1; + + /* parse fields */ + for (token = strtok(line, " "); + token != NULL; + token = strtok(NULL, " ")) { + if (token[0] == '\0') continue; /* skip empty strings */ + tag = token[0]; + value = token + 1; + switch (tag) { + case 'S': + switch(token[1]){ + case 'y': + case 'Y': + *sync = 1; + break; + case 'n': + case 'N': + *sync=0; + break; + default: + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: unknown sync tag setting\n"); + return 1; + } + break; + default: + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: unknown file tag\n"); + return 1; + } + } + } + + if(*sync==-1)return 1; + + return 0; +} + +typedef struct { + int valid; + int rate; + int ch; +} audio_info_t; + +typedef struct { + int valid; + int fps_n; + int fps_d; + int pa_n; + int pa_d; + int format; + int w; + int h; + int interlace; +} video_info_t; + +static int y4o_read_stream_header(stream_t *s, audio_info_t *a, video_info_t *v){ + char line[80]; + char *p; + int n,err; + ssize_t remain; + int af=0,vf=0,ff=0; + int orig_pos = stream_tell(s); + + memset(v,0,sizeof(*v)); + memset(a,0,sizeof(*a)); + + remain = read_wrap(s, line, sizeof("AUDIO")); + if (remain){ + if( remain > 0) + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: EOF reading stream header\n"); + return 1; + } + + if (!strncmp(line, "VIDEO ", sizeof("VIDEO ")-1)) vf=1; + else if (!strncmp(line, "AUDIO ", sizeof("AUDIO ")-1)) af=1; + else if (!strncmp(line, "FRAME ", sizeof("FRAME ")-1)) ff=1; + + if(! (af||vf||ff)){ + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: unknown stream header type\n"); + return 1; + } + + if(ff){ + stream_seek(s, orig_pos); + return -1; + } + + if(vf){ + /* video stream! */ + /* proceed to get the tags... (overwrite the magic) */ + for (n = 0, p = line; n < 80; n++, p++) { + if ((err=read_wrap(s, p, 1))){ + if(err>0) + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: EOF reading stream header\n"); + return 1; + } + if (*p == '\n') { + *p = '\0'; + break; + } + } + if (n >= 80) { + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: line too long reading stream header\n"); + return 1; + } + + /* read tags */ + /* W%d = width + H%d = height + F%d:%d = fps + I%c = interlace + A%d:%d = pixel aspect + C%s = chroma format + */ + + { + char *token, *value; + char tag; + int i; + v->format=-1; + v->interlace=-1; + + /* parse fields */ + for (token = strtok(line, " "); + token != NULL; + token = strtok(NULL, " ")) { + if (token[0] == '\0') continue; /* skip empty strings */ + tag = token[0]; + value = token + 1; + switch (tag) { + case 'W': + v->w = atoi(token+1); + break; + case 'H': + v->h = atoi(token+1); + break; + case 'F': + { + char *pos=strchr(token+1,':'); + if(pos){ + *pos='\0'; + v->fps_n = atoi(token+1); + v->fps_d = atoi(pos+1); + *pos=':'; + }else{ + v->fps_n = atoi(token+1); + v->fps_d = 1; + } + } + break; + case 'I': + switch(token[1]){ + case 'p': + case 'P': + v->interlace=0; + break; + case 't': + case 'T': + v->interlace=MP_IMGFIELD_ORDERED|MP_IMGFIELD_TOP_FIRST|MP_IMGFIELD_INTERLACED; + break; + case 'b': + case 'B': + v->interlace=MP_IMGFIELD_ORDERED|MP_IMGFIELD_INTERLACED; + break; + default: + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: unknown interlace setting\n"); + return 1; + } + case 'A': + { + char *pos=strchr(token+1,':'); + if(pos){ + *pos='\0'; + v->pa_n = atoi(token+1); + v->pa_d = atoi(pos+1); + *pos=':'; + }else{ + v->pa_n = atoi(token+1); + v->pa_d = 1; + } + } + break; + case 'C': + for(i=0;chromaformat[i];i++) + if(!strcasecmp(chromaformat[i],token+1))break; + if(!chromaformat[i]){ + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: unknown chroma format\n"); + return 1; + } + v->format=i; + break; + default: + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: unknown file tag\n"); + return 1; + } + } + } + + if(v->fps_n>0 && + v->fps_d>0 && + v->pa_n>0 && + v->pa_d>0 && + v->format>=0 && + v->w>0 && + v->h>0 && + v->interlace>=0) + v->valid=1; + else{ + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: missing flags in stream header\n"); + return 1; + } + return 0; + + } + + if(af){ + /* audio stream! */ + /* proceed to get the tags... (overwrite the magic) */ + for (n = 0, p = line; n < 80; n++, p++) { + if ((err=read_wrap(s, p, 1))){ + if(err>0) + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: EOF reading stream header\n"); + return 1; + } + if (*p == '\n') { + *p = '\0'; + break; + } + } + if (n >= 80) { + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: line too long reading stream header\n"); + return 1; + } + + /* read tags */ + /* R%d = rate + C%d = channels + all interchange audio is 24 bit signed LE + */ + + { + char *token, *value; + char tag; + + /* parse fields */ + for (token = strtok(line, " "); + token != NULL; + token = strtok(NULL, " ")) { + if (token[0] == '\0') continue; /* skip empty strings */ + tag = token[0]; + value = token + 1; + switch (tag) { + case 'R': + a->rate = atoi(token+1); + break; + case 'C': + a->ch = atoi(token+1); + break; + default: + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: unknown file tag\n"); + return 1; + } + } + } + + if(a->rate>0 && + a->ch>0) + a->valid=1; + else{ + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: missing flags in stream header\n"); + return 1; + } + return 0; + } + + return 0; +} + +static int y4o_read_frame_header(stream_t *s, int *streamno, int *length, double *pts, int complain){ + char line[80]; + char *p; + int n,err; + ssize_t remain; + + remain = read_wrap(s, line, sizeof("FRAME")); + if (remain != 0) + { + /* A clean EOF should end exactly at a frame-boundary */ + if( complain && remain > 0 && remain != sizeof("FRAME") ) + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: EOF reading frame\n"); + return 1; + } + + if (strncmp(line, "FRAME ", sizeof("FRAME ")-1)){ + if(complain) mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: loss of framing\n"); + return 1; + } + + /* proceed to get the tags... (overwrite the magic) */ + for (n = 0, p = line; n < 80; n++, p++) { + if ((err=read_wrap(s, p, 1))){ + if(err>0 && complain) + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: EOF reading frame\n"); + return 1; + } + if (*p == '\n') { + *p = '\0'; /* Replace linefeed by end of string */ + break; + } + } + if (n >= 80) { + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: line too long reading frame header\n"); + return 1; + } + + /* read tags */ + /* S%d = streamno + L%d = length + P%g = pts */ + + { + char *token, *value; + char tag; + + *streamno=-1; + *length=-1; + *pts=-1; + + /* parse fields */ + for (token = strtok(line, " "); + token != NULL; + token = strtok(NULL, " ")) { + if (token[0] == '\0') continue; /* skip empty strings */ + tag = token[0]; + value = token + 1; + switch (tag) { + case 'S': + *streamno = atoi(token+1); + break; + case 'L': + *length = atoi(token+1); + break; + case 'P': + *pts = atof(token+1); + break; + default: + mp_msg(MSGT_DEMUX, MSGL_FATAL, "[yuv4ogg] ERROR: unknown frame tag\n"); + return 1; + } + } + } + + if(*streamno==-1 || *length==-1 || *pts==-1)return 1; + + return 0; +} + +static int memnmem(unsigned char *b, unsigned char *str, int n, int m){ + int pos = 0; + unsigned char *f; + while(pos+m<=n && (f=memchr(b+pos,str[0],n-m-pos+1))!=NULL){ + int newpos = f-b; + if(strncmp(f,str,m)==0) return newpos; + pos=newpos+1; + } + return -1; +} + +static int y4o_reframe(stream_t *s){ + int streamno; + int length; + double pts; + + while(1){ + + /* read a page at a time, look for "FRAME " */ + int fill=0; + unsigned char buffer[4096+6]; + while(1){ + int ret=read_wrap(s,buffer+fill,4096+6-fill); + if(ret)return ret; + ret=memnmem(buffer,"FRAME ",4096+6,6); + if(ret>=0){ + /* return bytes to the stream */ + off_t pos = stream_tell(s)+ret-(4096+6); + stream_seek(s,pos); + + /* read a test frame header */ + if(y4o_read_frame_header(s, &streamno, &length, &pts, 0)){ + memcpy(buffer,buffer+4096,6); + fill=6; + continue; + } + + /* skip test frame */ + stream_seek(s,stream_tell(s)+length); + + /* read another test frame header */ + if(y4o_read_frame_header(s, &streamno, &length, &pts, 0)){ + memcpy(buffer,buffer+4096,6); + fill=6; + continue; + } + + /* we're good; go back to first frame pos */ + stream_seek(s,pos); + return 0; + } + memcpy(buffer,buffer+4096,6); + fill=6; + } + } +} + +// return value: +// 0 = EOF or no stream found +// 1 = successfully read a packet +static int demux_y4o_fill_buffer(demuxer_t *demux, demux_stream_t *dummy) { + demux_stream_t *ds=NULL; + int streamno,length; + double pts; + demux_packet_t *dp=NULL; + int err; + + demux->filepos=stream_tell(demux->stream); + + /* find a frame header; it will identify streamno */ + if (y4o_read_frame_header(demux->stream, &streamno, &length, &pts, 1)) return 0; + + /* we have a stream number and a PTS. continue raw 'decode' */ + if(streamno==demux->audio->id) + ds=demux->audio; + + if(streamno==demux->video->id) + ds=demux->video; + + if(!ds){ + stream_skip(demux->stream,length); + return 1; + } + + dp = new_demux_packet(length); + + if(ds==demux->video && dp){ + sh_video_t *sh = ds->sh; + + /* sadly, YUV video adds the complication of having to swap Cb and Cr + up front; we can't tell mplayer to do it itself at this layer*/ + int yl,ul,vl; + switch(sh->format){ + case 0x30303859: //Y800 + yl=length; + ul=vl=0; + break; + case 0x50313134: //411P + case 0x32315659: //YV12 + yl=length*2/3; + ul=vl=length/6; + break; + case 0x50323234: //422P + yl=length/2; + ul=vl=length/4; + break; + default: //444P + yl=ul=vl=length/3; + break; + } + + // Y + if((err=read_wrap(demux->stream,dp?dp->buffer:NULL,yl))){ + if(err>0) + mp_msg(MSGT_DEMUX, MSGL_V, "[yuv4ogg] error reading frame; EOF\n"); + return 0; + } + // U + if((err=read_wrap(demux->stream,dp?dp->buffer+yl+vl:NULL,ul))){ + if(err>0) + mp_msg(MSGT_DEMUX, MSGL_V, "[yuv4ogg] error reading frame; EOF\n"); + return 0; + } + // V + if((err=read_wrap(demux->stream,dp?dp->buffer+yl:NULL,vl))){ + if(err>0) + mp_msg(MSGT_DEMUX, MSGL_V, "[yuv4ogg] error reading frame; EOF\n"); + return 0; + } + + }else{ + if((err=read_wrap(demux->stream,dp?dp->buffer:NULL,length))){ + if(err>0) + mp_msg(MSGT_DEMUX, MSGL_V, "[yuv4ogg] error reading frame; EOF\n"); + return 0; + } + } + + dp->pts=pts; + dp->pos=demux->filepos; + dp->flags=0; + ds_add_packet(ds, dp); + + return 1; +} + +static demuxer_t* demux_open_y4o(demuxer_t* demuxer){ + y4o_priv_t *p = calloc(1,sizeof(*p)); + int sync; // unused for now + int streamno=0; + + int vid=-2; + int aid=-2; + + demuxer->priv=p; + + /* parse container header / tags */ + if(y4o_read_container_header(demuxer->stream, &sync)) + return NULL; + + /* parse stream headers / tags */ + while(1){ + audio_info_t a; + video_info_t v; + int ret = y4o_read_stream_header(demuxer->stream, &a, &v); + if(ret>0) return NULL; + if(ret<0) break; + + if(a.valid){ + /* audio stream! */ + sh_audio_t *sh=new_sh_audio(demuxer,streamno); + WAVEFORMATEX *w=sh->wf=calloc(1,sizeof(*w)); + w->wFormatTag = sh->format = 1; // AF_FORMAT_S24_LE; + w->nChannels = sh->channels = a.ch; + w->nSamplesPerSec = sh->samplerate = a.rate; + w->nAvgBytesPerSec = a.rate*a.ch*3; + w->nBlockAlign = 1; + w->wBitsPerSample = 24; + sh->samplesize = (w->wBitsPerSample + 7) / 8; + w->cbSize = 0; + sh->i_bps = sh->wf->nAvgBytesPerSec; + + if(demuxer->audio->id==-1){ + mp_msg(MSGT_DEMUX,MSGL_INFO,"[yuv4ogg] Auto-selected stream ID %d for audio\n",streamno); + demuxer->audio->id=streamno; + } + if(demuxer->audio->id==streamno){ + aid = streamno; + demuxer->audio->sh = sh; + sh->ds = demuxer->audio; + } + p->bytespersec += w->nAvgBytesPerSec; + } + + if(v.valid){ + /* video stream! */ + sh_video_t* sh=new_sh_video(demuxer,streamno); + int planes = 3; + int bpp = 12; + + if(!sh->fps) sh->fps = v.fps_n/(double)v.fps_d; + sh->frametime=1.0f/sh->fps; + + sh->disp_w = v.w; + sh->disp_h = v.h; + sh->aspect = (float)(sh->disp_w*v.pa_n)/(float)(sh->disp_h*v.pa_d); + sh->fields = v.interlace; + switch(v.format){ + case Cmono: + sh->format = 0x30303859; //Y800 + planes = 1; + bpp = 8; + break; + case C411ntscdv: + sh->format = 0x50313134; //411P + break; + case C420jpeg: + case C420mpeg2: + case C420paldv: + case C420unknown: + sh->format = 0x32315659; //YV12 + break; + case C422jpeg: + case C422smpte: + case C422unknown: + sh->format = 0x50323234; //422P + bpp = 16; + break; + case C444: + default: + sh->format = 0x50343434; //444P + bpp = 24; + break; + } + + sh->bih=calloc(1,sizeof(*sh->bih)); + sh->bih->biSize=sizeof(*sh->bih); + sh->bih->biWidth = sh->disp_w; + sh->bih->biHeight = sh->disp_h; + sh->bih->biPlanes = planes; + sh->bih->biBitCount = bpp; + sh->bih->biCompression = sh->format; + sh->bih->biSizeImage = sh->bih->biWidth*sh->bih->biHeight*bpp/8; + + if(demuxer->video->id==-1){ + mp_msg(MSGT_DEMUX,MSGL_INFO,"[yuv4ogg] Auto-selected stream ID %d for video\n",streamno); + demuxer->video->id=streamno; + } + if(demuxer->video->id==streamno){ + vid = streamno; + demuxer->video->sh = sh; + sh->ds = demuxer->video; + } + p->bytespersec += v.w*v.h*bpp/8.*v.fps_n/v.fps_d; + } + + streamno++; + p->streams++; + } + + demuxer->video->id=vid; + demuxer->audio->id=aid; + + if(demuxer->video->id != -2){ + sh_video_t* sh=demuxer->video->sh; + + if(!ds_fill_buffer(demuxer->video)){ + mp_msg(MSGT_DEMUXER,MSGL_WARN,"[yuv4ogg] " MSGTR_MissingVideoStream); + demuxer->video->sh=NULL; + } + + mp_msg(MSGT_DEMUX, MSGL_INFO, "YUV4OGG Video stream %d size: display: %dx%d, coded: %ux%u\n", + demuxer->video->id, sh->disp_w, sh->disp_h, sh->bih->biWidth, + sh->bih->biHeight); + } + + if(demuxer->audio->id != -2) + if(!ds_fill_buffer(demuxer->audio)){ + mp_msg(MSGT_DEMUXER,MSGL_INFO,"[yuv4ogg] " MSGTR_MissingAudioStream); + demuxer->audio->sh=NULL; + } + + return demuxer; +} + +static void demux_seek_y4o(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags) { + y4o_priv_t *p = (y4o_priv_t *)demuxer->priv; + off_t newpos; + + if(flags&SEEK_ABSOLUTE) + newpos = rel_seek_secs*p->bytespersec; + else + newpos = stream_tell(demuxer->stream) + rel_seek_secs*p->bytespersec; + + if(newpos<0)newpos=0; + stream_seek(demuxer->stream,newpos); + + /* find the next proper frame */ + if(y4o_reframe(demuxer->stream)) + return; // EOF or EIO + + /* fill buffers */ + if(demuxer->video->id >= 0) + ds_fill_buffer(demuxer->video); + if(demuxer->audio->sh) + ds_fill_buffer(demuxer->audio); + + /* we do *not* attempt to 'resyc' audio as the typical y4o file that + hasn't been through a resync util will have occasional completely + insane PTS entries. However, because y4os tend to be written by + converters that are actually players at heart, the interleave + will be close to correct. It should be unusual to have initial + resync off by more than a few hundred ms, and mplayer will close + that difference quickly. + */ + +} + +static void demux_close_y4o(demuxer_t *demuxer){ + free(demuxer->priv); +} + + +const demuxer_desc_t demuxer_desc_y4o = { + "YUV4OGG demuxer", + "y4o", + "YUV4OGG", + "Monty ", + "", + DEMUXER_TYPE_Y4O, + 1, // safe autodetect + demux_y4o_id, + demux_y4o_fill_buffer, + demux_open_y4o, + demux_close_y4o, + demux_seek_y4o, + NULL +}; diff -ruNX mplayer-exclude mplayer-svn/libmpdemux/stheader.h mplayer-svn-monty/libmpdemux/stheader.h --- mplayer-svn/libmpdemux/stheader.h 2009-07-18 17:24:35.916868875 -0400 +++ mplayer-svn-monty/libmpdemux/stheader.h 2009-07-14 10:03:15.000000000 -0400 @@ -97,6 +97,7 @@ float stream_aspect; // aspect ratio stored in the media headers (e.g. in DVD IFO files) int i_bps; // == bitrate (compressed bytes/sec) int disp_w,disp_h; // display size (filled by fileformat parser) + int fields; // interlacing set by container on raw formats (eg, yuv4ogg) // output driver/filters: (set by libmpcodecs core) unsigned int outfmtidx; struct vf_instance_s *vfilter; // the video filter chain, used for this video stream diff -ruNX mplayer-exclude mplayer-svn/libvo/vo_xv.c mplayer-svn-monty/libvo/vo_xv.c --- mplayer-svn/libvo/vo_xv.c 2009-07-18 17:24:18.248908827 -0400 +++ mplayer-svn-monty/libvo/vo_xv.c 2009-08-08 15:43:55.262668431 -0400 @@ -722,7 +722,7 @@ { return -1; // bail out, colorkey setup failed } - vo_xv_enable_vsync(); + vo_xv_set_vsync(); vo_xv_get_max_img_dim( &max_width, &max_height ); fo = XvListImageFormats(mDisplay, xv_port, (int *) &formats); diff -ruNX mplayer-exclude mplayer-svn/libvo/vo_xvmc.c mplayer-svn-monty/libvo/vo_xvmc.c --- mplayer-svn/libvo/vo_xvmc.c 2009-07-18 17:24:18.242908928 -0400 +++ mplayer-svn-monty/libvo/vo_xvmc.c 2009-08-08 15:44:39.834674041 -0400 @@ -615,7 +615,7 @@ return -1; // bail out, colorkey setup failed } - vo_xv_enable_vsync();//it won't break anything + vo_xv_set_vsync();//it won't break anything //taken from vo_xv image_height = height; diff -ruNX mplayer-exclude mplayer-svn/libvo/x11_common.c mplayer-svn-monty/libvo/x11_common.c --- mplayer-svn/libvo/x11_common.c 2009-07-18 17:24:18.216908854 -0400 +++ mplayer-svn-monty/libvo/x11_common.c 2009-07-15 12:36:17.816223899 -0400 @@ -85,6 +85,7 @@ #define WIN_LAYER_ONTOP 6 #define WIN_LAYER_ABOVE_DOCK 10 +extern int fast; extern int enable_mouse_movements; int fs_layer = WIN_LAYER_ABOVE_DOCK; static int orig_layer = 0; @@ -2057,15 +2058,15 @@ } /** - * \brief Try to enable vsync for xv. + * \brief Try to enable vsync for xv, but only if 'fast' is unset, otherwise turn it off. * \return Returns -1 if not available, 0 on failure and 1 on success. */ -int vo_xv_enable_vsync(void) +int vo_xv_set_vsync() { Atom xv_atom = xv_intern_atom_if_exists("XV_SYNC_TO_VBLANK"); if (xv_atom == None) return -1; - return XvSetPortAttribute(mDisplay, xv_port, xv_atom, 1) == Success; + return XvSetPortAttribute(mDisplay, xv_port, xv_atom, !fast) == Success; } /** diff -ruNX mplayer-exclude mplayer-svn/libvo/x11_common.h mplayer-svn-monty/libvo/x11_common.h --- mplayer-svn/libvo/x11_common.h 2009-07-18 17:24:18.217908971 -0400 +++ mplayer-svn-monty/libvo/x11_common.h 2009-07-15 12:32:32.484351450 -0400 @@ -102,7 +102,7 @@ int vo_xv_set_eq(uint32_t xv_port, char * name, int value); int vo_xv_get_eq(uint32_t xv_port, char * name, int *value); -int vo_xv_enable_vsync(void); +int vo_xv_enable_vsync(int v); void vo_xv_get_max_img_dim( uint32_t * width, uint32_t * height ); diff -ruNX mplayer-exclude mplayer-svn/Makefile mplayer-svn-monty/Makefile --- mplayer-svn/Makefile 2009-07-18 17:26:18.524908852 -0400 +++ mplayer-svn-monty/Makefile 2009-08-13 02:29:14.681700093 -0400 @@ -373,6 +373,7 @@ libaf/af_tools.c \ libaf/af_volnorm.c \ libaf/af_volume.c \ + libaf/af_yuv4ogg.c \ libaf/filter.c \ libaf/format.c \ libaf/reorder_ch.c \ @@ -425,6 +426,7 @@ libmpcodecs/vf_flip.c \ libmpcodecs/vf_format.c \ libmpcodecs/vf_framestep.c \ + libmpcodecs/vf_framemerge.c \ libmpcodecs/vf_gradfun.c \ libmpcodecs/vf_halfpack.c \ libmpcodecs/vf_harddup.c \ @@ -435,6 +437,7 @@ libmpcodecs/vf_ivtc.c \ libmpcodecs/vf_kerndeint.c \ libmpcodecs/vf_mirror.c \ + libmpcodecs/vf_nailfps.c \ libmpcodecs/vf_noformat.c \ libmpcodecs/vf_noise.c \ libmpcodecs/vf_ow.c \ @@ -462,6 +465,7 @@ libmpcodecs/vf_unsharp.c \ libmpcodecs/vf_vo.c \ libmpcodecs/vf_yadif.c \ + libmpcodecs/vf_yuv4ogg.c \ libmpcodecs/vf_yuvcsp.c \ libmpcodecs/vf_yuy2.c \ libmpcodecs/vf_yvu9.c \ @@ -496,6 +500,7 @@ libmpdemux/demux_viv.c \ libmpdemux/demux_vqf.c \ libmpdemux/demux_y4m.c \ + libmpdemux/demux_y4o.c \ libmpdemux/ebml.c \ libmpdemux/extension.c \ libmpdemux/mf.c \ diff -ruNX mplayer-exclude mplayer-svn/mencoder.c mplayer-svn-monty/mencoder.c --- mplayer-svn/mencoder.c 2009-07-18 17:24:42.701908870 -0400 +++ mplayer-svn-monty/mencoder.c 2009-07-14 04:03:41.000000000 -0400 @@ -86,6 +86,8 @@ #endif #include "libmpcodecs/ae.h" +extern void y4o_exit(); + int vo_doublebuffering=0; int vo_directrendering=0; int vo_config_count=1; @@ -154,6 +156,7 @@ static int audio_density=2; double force_fps=0; +float vo_fps=0; static double force_ofps=0; // set to 24 for inverse telecine static int skip_limit=-1; float playback_speed=1.0; @@ -321,13 +324,13 @@ //--------------------------------------------------------------------------- -static int dec_audio(sh_audio_t *sh_audio,unsigned char* buffer,int total){ +static int dec_audio(sh_audio_t *sh_audio,unsigned char* buffer,int total,double pts){ int size=0; int at_eof=0; while(sizeMAX_OUTBURST) len=MAX_OUTBURST; - if (decode_audio(sh_audio, len) < 0) at_eof=1; + if (decode_audio(sh_audio, len, pts) < 0) at_eof=1; if(len>sh_audio->a_out_buffer_len) len=sh_audio->a_out_buffer_len; fast_memcpy(buffer+size,sh_audio->a_out_buffer,len); sh_audio->a_out_buffer_len-=len; size+=len; @@ -603,6 +606,7 @@ sh_video->frametime=1.0f/sh_video->fps; mp_msg(MSGT_MENCODER,MSGL_INFO,MSGTR_ForcingInputFPS, sh_video->fps); } + vo_fps = sh_video->fps; if(sh_audio && out_audio_codec<0){ if(audio_id==-2) @@ -1146,7 +1150,7 @@ else len = aencoder->decode_buffer_size; - len = dec_audio(sh_audio, aencoder->decode_buffer, len); + len = dec_audio(sh_audio, aencoder->decode_buffer, len, mux_a->timer); mux_a->buffer_len += aencoder->encode(aencoder, mux_a->buffer + mux_a->buffer_len, aencoder->decode_buffer, len, mux_a->buffer_size-mux_a->buffer_len); if(mux_a->buffer_len < mux_a->wf->nBlockAlign) @@ -1167,7 +1171,7 @@ len = sz; break; } - len = dec_audio(sh_audio,aencoder->decode_buffer, aencoder->decode_buffer_size); + len = dec_audio(sh_audio,aencoder->decode_buffer, aencoder->decode_buffer_size, mux_a->timer); if(len <= 0) { len = 0; @@ -1540,6 +1544,7 @@ if(sh_video){ uninit_video(sh_video);sh_video=NULL; } if(demuxer) free_demuxer(demuxer); if(stream) free_stream(stream); // kill cache thread +y4o_exit(); return interrupted; } diff -ruNX mplayer-exclude mplayer-svn/mplayer.c mplayer-svn-monty/mplayer.c --- mplayer-svn/mplayer.c 2009-07-18 17:24:42.679908366 -0400 +++ mplayer-svn-monty/mplayer.c 2009-07-15 13:13:33.474148318 -0400 @@ -77,7 +77,9 @@ #endif #include "input/input.h" +#include "libmpcodecs/vf_yuv4ogg.h" +int fast=0; int slave_mode=0; int player_idle_mode=0; int quiet=0; @@ -2002,11 +2004,13 @@ { unsigned int t; double tt; + double af_pts; int playsize; int playflags=0; int audio_eof=0; int bytes_to_write; sh_audio_t * const sh_audio = mpctx->sh_audio; + demux_stream_t * const d_audio = mpctx->d_audio; current_module="play_audio"; @@ -2037,7 +2041,39 @@ // Fill buffer if needed: current_module="decode_audio"; t = GetTimer(); - if (decode_audio(sh_audio, playsize) < 0) // EOF or error + + af_pts = sh_audio->pts; + if (af_pts != MP_NOPTS_VALUE) + // Good, decoder supports new way of calculating audio pts. + // sh_audio->pts is the timestamp of the latest input packet with + // known pts that the decoder has decoded. sh_audio->pts_bytes is + // the amount of bytes the decoder has written after that timestamp. + af_pts += sh_audio->pts_bytes / (double) sh_audio->o_bps; + else { + // Decoder doesn't support new way of calculating pts (or we're + // being called before it has decoded anything with known timestamp). + // Use the old method of audio pts calculation: take the timestamp + // of last packet with known pts the decoder has read data from, + // and add amount of bytes read after the beginning of that packet + // divided by input bps. This will be inaccurate if the input/output + // ratio is not constant for every audio packet or if it is constant + // but not accurately known in sh_audio->i_bps. + + af_pts = d_audio->pts; + // ds_tell_pts returns bytes read after last timestamp from + // demuxing layer, decoder might use sh_audio->a_in_buffer for bytes + // it has read but not decoded + if (sh_audio->i_bps) + af_pts += (ds_tell_pts(d_audio) - sh_audio->a_in_buffer_len) / + (double)sh_audio->i_bps; + } + // Now a_pts hopefully holds the pts for end of audio from decoder. + // Substract data in buffers between decoder and audio out. + + // Decoded but not filtered + af_pts -= sh_audio->a_buffer_len / (double)sh_audio->o_bps; + + if (decode_audio(sh_audio, playsize, af_pts) < 0) // EOF or error if (mpctx->d_audio->eof) { audio_eof = 1; if (sh_audio->a_out_buffer_len == 0) @@ -2127,10 +2163,13 @@ //============================== SLEEP: =================================== - - // flag 256 means: libvo driver does its timing (dvb card) - if (*time_frame > 0.001 && !(vo_flags&256)) + if(fast){ + *time_frame=0; + }else{ + // flag 256 means: libvo driver does its timing (dvb card) + if (*time_frame > 0.001 && !(vo_flags&256)) *time_frame = timing_sleep(*time_frame); + } return frame_time_remaining; } @@ -3751,7 +3790,7 @@ //============================ Auto QUALITY ============================ /*Output quality adjustments:*/ -if(auto_quality>0){ +if(auto_quality>0 && !fast){ current_module="autoq"; // float total=0.000001f * (GetTimer()-aq_total_time); // if(output_quality0.05f*total) @@ -4006,6 +4045,7 @@ goto play_next_file; } +y4o_exit(); exit_player_with_rc(EXIT_EOF, 0); Binary files mplayer-svn/repaired.asf and mplayer-svn-monty/repaired.asf differ