|
View:
New views
5 Messages
—
Rating Filter:
Alert me
|
|
|
PATCH: Add support for CoreAVC via dshowserverI was asked to send this patch to xine-devel by Darren Salt.
It implements support for communicating with the dshowserver (coreavc-for-linux.googlecode.com) This is mainly useful for using CoreAVC in Linux (a very fast H264 decoder), however it could be made to work with other win32 codecs. The code is based on mplayer's libloader (which xine already includes in modified form) but using a separate server allows for several benefits: a) easy to support in multiple players (mythtv, xine, mplayer) since the dshowserver patch is small, and all the win32 stuff is centralized b) can use 32bit win32 codecs with players compiled in 64-bit mode c) a crash in the codec does not bring down the player I have addressed many of the issues he requested I address except for: * The plugin description should be translatable (use N_() for this) I don't see any examples of other plugins doing this, so I wasn't sure how to proceed. * Documentation patches I have no idea what he wanted here. * Fixed-size buffers should be avoided wherever practical, e.g. use asprintf() where it makes sense to do so. I did move the constant-sized strings (snprintf) to use asprintf as requested, but this really didn't feel like the right thing to do to me. The code is built against the xinelib 1.1 branch, and will require a some change to work in 1.2 diff -r 66e1654718fb configure.ac --- a/configure.ac Mon Apr 14 22:38:03 2008 +0200 +++ b/configure.ac Tue Jun 24 14:06:43 2008 -0700 @@ -2538,6 +2538,14 @@ fi AM_CONDITIONAL(HAVE_W32DLL, test "x$enable_w32dll" != "xno") +AC_ARG_ENABLE([dshowserver], + AS_HELP_STRING([--disable-dshowserver], [Disable dshowserver support])) + +if test "x$arch_x86" == "xno"; then + enable_dshowserver="no" +fi + +AM_CONDITIONAL(HAVE_DSHOWSERVER, test "x$enable_dshowserver" != "xno") dnl --------------------------------------------- dnl some include paths ( !!! DO NOT REMOVE !!! ) diff -r 66e1654718fb src/libxinevdec/Makefile.am --- a/src/libxinevdec/Makefile.am Mon Apr 14 22:38:03 2008 +0200 +++ b/src/libxinevdec/Makefile.am Tue Jun 24 14:06:43 2008 -0700 @@ -17,9 +17,14 @@ theora_module = xineplug_decode_theora.l theora_module = xineplug_decode_theora.la endif +if HAVE_DSHOWSERVER +dshowserver_module = xineplug_decode_dshowserver.la +endif + xineplug_LTLIBRARIES = $(image_module) \ $(gdkpixbuf_module) \ $(theora_module) \ + $(dshowserver_module) \ xineplug_decode_bitplane.la \ xineplug_decode_rgb.la \ xineplug_decode_yuv.la @@ -44,3 +49,7 @@ xineplug_decode_theora_la_SOURCES = xine xineplug_decode_theora_la_SOURCES = xine_theora_decoder.c xineplug_decode_theora_la_CFLAGS = $(AM_CFLAGS) $(OGG_CFLAGS) $(THEORA_CFLAGS) xineplug_decode_theora_la_LIBADD = $(XINE_LIB) $(OGG_LIBS) $(THEORA_LIBS) + +xineplug_decode_dshowserver_la_SOURCES = dshowserver.c nal_parser.c +xineplug_decode_dshowserver_la_LIBADD = $(XINE_LIB) $(RT_LIBS) $(PTHREAD_LIBS) +noinst_HEADERS = nal_parser.h diff -r 66e1654718fb src/libxinevdec/dshowserver.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libxinevdec/dshowserver.c Tue Jun 24 14:06:43 2008 -0700 @@ -0,0 +1,440 @@ +/* + * Copyright (C) 2008 Alan Nisota + * + * This file is part of xine, a free video player. + * + * xine 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. + * + * xine 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Support for dshowserver, which enables using w32 codecs in a seperate process. + * This is useful to run 32bit codecs in a 64bit xine. + * It is mostly tageted at supporting CoreAVC at the moment. + */ +#define _GNU_SOURCE //needed for asprintf +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> + +#include <semaphore.h> +#include <pthread.h> +#include <sys/mman.h> + +#include "xine_internal.h" +#include "video_out.h" +#include "buffer.h" +#include "xineutils.h" + +#include "nal_parser.h" + +struct vd_struct { + union { + uint32_t ret; + uint32_t cmd; + }; + uint32_t buflen; + uint64_t pts; + uint32_t unused[8]; +} __attribute__((__packed__)); + +enum { + VD_END = 1, + VD_DECODE = 2, + VD_SEEK = 3, + VD_RELOAD_BIH = 4, + VD_HAS_BIH = 0x10000, + VD_VERSION_MASK = 0xFFFF, +}; + +typedef struct { + int fd; + void *mem; + char *data; + char *picture; + char *pagestart; + int picsize; + int pagesize; + sem_t *sem_rd; + sem_t *sem_wr; + struct vd_struct *vd; +} ds_mpi_t; + +typedef struct { + video_decoder_class_t decoder_class; +} dshowserver_class_t; + +typedef struct { + video_decoder_t video_decoder; + + xine_stream_t *stream; + dshowserver_class_t *class; + + int64_t video_step; + int decoder_ok; + int decoder_initialized; + + int stream_id; + int skipframes; + + int size; /* the current size of buf */ + int width; /* the width of a video frame */ + int height; /* the height of a video frame */ + uint32_t compression; /* the compression format */ + double ratio; /* the width to height ratio */ + int bpp; + int numpages; + int extra; /* width & 0x0f */ + ds_mpi_t ds_mpi; + + xine_bmiheader *bih; + unsigned char *extradata; + int extradata_size; + struct nal_parser *parser; /* Parser for H264 */ + +} dshowserver_decoder_t; + +static int sem_twait(sem_t *sem, int t) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += t; + return(sem_timedwait(sem, &ts)); +} + +static void make_bih(dshowserver_decoder_t *this) +{ + if(this->bih) { + this->bih = realloc(this->bih, sizeof(xine_bmiheader) + this->extradata_size); + } else { + this->bih = xine_xmalloc(sizeof(xine_bmiheader) + this->extradata_size); + this->bih->biWidth = this->width; + this->bih->biHeight = this->height; + this->bih->biPlanes = 1; + this->bih->biBitCount = 24; + this->bih->biCompression = this->compression; + this->bih->biSizeImage = 0; + this->bih->biXPelsPerMeter=10000; + this->bih->biYPelsPerMeter=10000; + this->bih->biClrUsed=0; + this->bih->biClrImportant=0; + } + if(this->extradata_size) + memcpy((unsigned char *)this->bih + sizeof(xine_bmiheader), this->extradata, this->extradata_size); + this->bih->biSize = sizeof(xine_bmiheader) + this->extradata_size; +} + +static void dshowserver_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { + dshowserver_decoder_t *this = (dshowserver_decoder_t *) this_gen; + int ret = 0; + vo_frame_t *img = 0; /* video out frame */ + int size_from_nal = 0; + + lprintf ("processing packet type = %08x, buf->decoder_flags=%08x\n", + buf->type, buf->decoder_flags); + + if (buf->decoder_flags & BUF_FLAG_PREVIEW) + return; + + if (buf->decoder_flags & BUF_FLAG_FRAMERATE) { + this->video_step = buf->decoder_info[0]; + _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->video_step); + + lprintf ("video_step is %lld\n", this->video_step); + } + + if (buf->decoder_flags & BUF_FLAG_SPECIAL) { + /* store extradata */ + if (buf->decoder_info[1] == BUF_SPECIAL_DECODER_CONFIG && + !this->extradata_size) + { + lprintf("BUF_SPECIAL_DECODER_CONFIG\n"); + this->extradata_size = buf->decoder_info[2]; + this->extradata = xine_xmalloc(buf->decoder_info[2]); + memcpy(this->extradata, buf->decoder_info_ptr[2], + buf->decoder_info[2]); + lprintf("Extradata: %d\n", this->extradata_size); + } + } + + if(! this->decoder_ok && ! (buf->decoder_flags & BUF_FLAG_STDHEADER)) { + int len = 0; + unsigned char *tmpbuf; + int tmplen; + if(! this->parser) + this->parser = init_parser(); + + while(len < buf->size) { + len += parse_frame(this->parser, buf->content + len, buf->size - len, + &tmpbuf, &tmplen); + if(tmpbuf) + free(tmpbuf); + if(this->parser->current_nal->sps != NULL) + { + this->width = this->parser->current_nal->sps->pic_width; + this->height = this->parser->current_nal->sps->pic_height; + this->compression = 0x34363248; //H264 + size_from_nal = 1; + } + } + } + if (! this->decoder_ok && (buf->decoder_flags & BUF_FLAG_STDHEADER || size_from_nal)) { + if(! size_from_nal) { + int size = ((xine_bmiheader *) buf->content)->biSize; + this->bih = xine_xmalloc(size); + memcpy(this->bih, buf->content, size); + this->width = this->bih->biWidth; + this->height = this->bih->biHeight; + this->compression = this->bih->biCompression; + } + this->extra = this->width & 0x0F; + this->bpp = 16; //YUY2 + this->numpages = 10; + + if ( buf->type & 0xff ) + return; + + lprintf ("processing header ...\n"); + + /* init package containing bih */ + + this->ratio = (double)this->width/(double)this->height; + + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->width); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->height); + + //Do dshowserver init here + this->decoder_ok = 1; + + if (! this->decoder_ok) { + xine_log (this->stream->xine, XINE_LOG_MSG, + _("dshowserver: decoder failed to start\n")); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HANDLED, 0); + _x_message(this->stream, XINE_MSG_LIBRARY_LOAD_ERROR, + "dshowserver", NULL); + } + } else if (this->decoder_ok) { + lprintf ("processing packet ...\n"); + if(! this->decoder_initialized) { + //delay initialization until 1st frame in case extradata comes. + int memsize = 0; + char *cmd, *shm, *sem1, *sem2; + + this->decoder_initialized = 1; + asprintf(&cmd, "dshowserver -c CoreAVCDecoder.ax -s %dx%d " + "-g 09571a4b-f1fe-4c60-9760de6d310c7c31 " + "-f 0x%08x -b %d -o 0x%08x -p %d -i %x -n %d %s&", + this->width, this->height, + this->compression, this->bpp, XINE_IMGFMT_YUY2, getpid(), + *(int *)pthread_self(), this->numpages, ""); + asprintf(&shm, "/dshow_shm.%x", *(int *)pthread_self()); + asprintf(&sem1, "/dshow_sem1.%x", *(int *)pthread_self()); + asprintf(&sem2, "/dshow_sem2.%x", *(int *)pthread_self()); + + this->ds_mpi.fd = shm_open(shm, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + this->ds_mpi.picsize = this->width * this->height * this->bpp / 8; + this->ds_mpi.pagesize = this->ds_mpi.picsize + 1024; + memsize = sizeof(struct vd_struct) + this->width * this->height + this->ds_mpi.picsize + this->extra + this->ds_mpi.pagesize * this->numpages; + ftruncate(this->ds_mpi.fd, memsize); + this->ds_mpi.mem = mmap(NULL, memsize, PROT_READ | PROT_WRITE, MAP_SHARED, this->ds_mpi.fd, 0); + if(this->ds_mpi.mem == MAP_FAILED) { + xine_log (this->stream->xine, XINE_LOG_MSG, _("dschowserver: mmap failed\n")); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HANDLED, 0); + _x_message(this->stream, XINE_MSG_LIBRARY_LOAD_ERROR, + "dshowserver", NULL); + return; + } + memset((char *)this->ds_mpi.mem, 0, sizeof(struct vd_struct)); + this->ds_mpi.vd = (struct vd_struct *)this->ds_mpi.mem; + this->ds_mpi.data = ((char *)this->ds_mpi.mem) + sizeof(struct vd_struct); + this->ds_mpi.picture = this->ds_mpi.data + this->width * this->height; + this->ds_mpi.pagestart = this->ds_mpi.picture + this->ds_mpi.picsize + this->extra; + if (this->extra) + memset((char *)this->ds_mpi.picture + this->ds_mpi.picsize, 0, this->extra); + + if(this->extradata) + make_bih(this); + if(this->bih && this->bih->biSize > sizeof(xine_bmiheader)) { + this->ds_mpi.vd->cmd |= VD_HAS_BIH; //Use embedded bih + memcpy(this->ds_mpi.data, this->bih, this->bih->biSize); + } + //Create read/write semaphores in locked state + this->ds_mpi.sem_wr = sem_open(sem1, O_CREAT, 0644, 0); + this->ds_mpi.sem_rd = sem_open(sem2, O_CREAT, 0644, 0); + system(cmd); + ret = sem_twait(this->ds_mpi.sem_rd, 10); + shm_unlink(shm); + sem_unlink(sem1); + sem_unlink(sem2); + free(cmd); + free(shm); + free(sem1); + free(sem2); + if(ret != 0) { + xine_log (this->stream->xine, XINE_LOG_MSG, + _("dshowserver: decoder failed to start\n")); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HANDLED, 0); + _x_message(this->stream, XINE_MSG_LIBRARY_LOAD_ERROR, + "dshowserver", NULL); + return; + } + lprintf("Found DirectShow filter\n"); + } + + if( (int) buf->size <= 0 ) + return; + + if( this->stream_id < 0 ) + this->stream_id = buf->type & 0xff; + + if( this->stream_id != (buf->type & 0xff) ) + return; + + xine_fast_memcpy (this->ds_mpi.data + this->size, buf->content, buf->size); + this->size += buf->size; + if (! (buf->decoder_flags & BUF_FLAG_FRAME_END)) + return; + this->ds_mpi.vd->cmd = VD_DECODE; //'2' is cmd for decoding + this->ds_mpi.vd->pts = buf->pts; + this->ds_mpi.vd->buflen = this->size; + this->size = 0; + sem_post(this->ds_mpi.sem_wr); + ret = sem_twait(this->ds_mpi.sem_rd, 10); + lprintf("ret: %d/%d PTS: %lld -> %lld\n", ret, this->ds_mpi.vd->ret, buf->pts, this->ds_mpi.vd->pts); + //lprintf("PTS (%d): %f(%d) -> %d\n", this->ds_mpi.vd->ret, sh->buffered_pts[0], pts-1, this->ds_mpi.vd->pts); + if(ret == 0 && this->ds_mpi.vd->ret && ! (this->ds_mpi.vd->ret & (1<<31))) { + int flags = VO_BOTH_FIELDS; + if(this->ds_mpi.vd->ret & 0x10) + flags |= VO_INTERLACED_FLAG; + else + flags &= ~VO_INTERLACED_FLAG; + + img = this->stream->video_out->get_frame (this->stream->video_out, + this->width, this->height, + this->ratio, XINE_IMGFMT_YUY2, + flags); + if(this->ds_mpi.vd->pts) + img->pts = this->ds_mpi.vd->pts; + else + img->pts = buf->pts; + img->bad_frame = 0; + img->duration = this->video_step; + if(this->ds_mpi.vd->ret & 0x02) { + unsigned char page = this->ds_mpi.vd->ret >> 8; + memcpy(img->base[0], this->ds_mpi.pagestart + page * this->ds_mpi.pagesize, this->ds_mpi.picsize); + } else { + memcpy(img->base[0], this->ds_mpi.picture, this->ds_mpi.picsize); + } + img->draw(img, this->stream); + img->free(img); + } + } +} + +/* flush gets called by video-decoder to force outputting frames (?) */ +static void dshowserver_flush (video_decoder_t *this_gen) { +} + +/* reset seems to be called after a seek */ +static void dshowserver_reset (video_decoder_t *this_gen) { + dshowserver_decoder_t *this = (dshowserver_decoder_t *) this_gen; + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "dshowserver: called reset\n"); + if(this->decoder_initialized) { + this->ds_mpi.vd->cmd = VD_SEEK; //'3' is cmd for seek + sem_post(this->ds_mpi.sem_wr); + sem_twait(this->ds_mpi.sem_rd, 10); + } + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "dshowserver: reset done\n"); +} + +static void dshowserver_discontinuity (video_decoder_t *this_gen) { +} + +static void dshowserver_dispose (video_decoder_t *this_gen) { + dshowserver_decoder_t *this = (dshowserver_decoder_t *) this_gen; + if( this->decoder_initialized ) { + this->decoder_ok = 0; + this->stream->video_out->close(this->stream->video_out, this->stream); + this->ds_mpi.vd->cmd = VD_END; //'1' is cmd for terminating + sem_post(this->ds_mpi.sem_wr); + close(this->ds_mpi.fd); + sem_close(this->ds_mpi.sem_wr); + sem_close(this->ds_mpi.sem_rd); + } + if(this->parser) + free_parser(this->parser); + if(this->bih) + free(this->bih); + free (this); +} + +static video_decoder_t *open_plugin (video_decoder_class_t *class_gen, xine_stream_t *stream) { + + dshowserver_decoder_t *this = (dshowserver_decoder_t *) xine_xmalloc (sizeof (dshowserver_decoder_t)); + + this->video_decoder.decode_data = dshowserver_decode_data; + this->video_decoder.flush = dshowserver_flush; + this->video_decoder.reset = dshowserver_reset; + this->video_decoder.discontinuity = dshowserver_discontinuity; + this->video_decoder.dispose = dshowserver_dispose; + + this->stream = stream; + this->class = (dshowserver_class_t *) class_gen; + + this->decoder_ok = 0; + return &this->video_decoder; +} + +static char *get_identifier (video_decoder_class_t *this) { + return "dshowserver"; +} + +static char *get_description (video_decoder_class_t *this) { + return "Dshowserver video decoder plugin (mostly used for CoreAVC windows codec)"; +} + +static void dispose_class (video_decoder_class_t *this) { + free (this); +} + +static void *init_plugin (xine_t *xine, void *data) { + + dshowserver_class_t *this = (dshowserver_class_t *) xine_xmalloc (sizeof (dshowserver_class_t)); + + this->decoder_class.open_plugin = open_plugin; + this->decoder_class.get_identifier = get_identifier; + this->decoder_class.get_description = get_description; + this->decoder_class.dispose = dispose_class; + + return this; +} + +static uint32_t video_types[] = { + BUF_VIDEO_H264, + 0 +}; + +static const decoder_info_t dec_info_video = { + video_types, /* supported types */ + 1 /* priority */ +}; + +const plugin_info_t xine_plugin_info[] EXPORTED = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_VIDEO_DECODER, 18, "dshowserver", XINE_VERSION_CODE, &dec_info_video, init_plugin }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; diff -r 66e1654718fb src/libxinevdec/nal_parser.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libxinevdec/nal_parser.c Tue Jun 24 14:06:43 2008 -0700 @@ -0,0 +1,520 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "nal_parser.h" + +struct buf_reader { + uint8_t *buf; + uint8_t *cur_pos; + int len; + int cur_offset; +}; + +static inline uint32_t read_bits(struct buf_reader *buf, int len); +uint32_t read_exp_golomb(struct buf_reader *buf); +int32_t read_exp_golomb_s(struct buf_reader *buf); +void skip_scaling_list(struct buf_reader *buf, int size); +int parse_nal_header(struct buf_reader *buf, struct nal_unit *nal); +uint8_t parse_sps(struct buf_reader *buf, struct seq_parameter_set_rbsp *sps); +uint8_t parse_pps(struct buf_reader *buf, struct pic_parameter_set_rbsp *pps); +uint8_t parse_slice_header(struct buf_reader *buf, struct nal_unit *nal); + + +static void decode_nal(uint8_t **ret, int *len_ret, uint8_t *buf, int buf_len) +{ + uint8_t *end = &buf[buf_len]; + uint8_t *pos = malloc(buf_len); + + *ret = pos; + while(buf < end) { + if(buf < end - 3 && buf[0] == 0x00 && buf[1] == 0x00 && + buf[2] == 0x03) { + + *pos++ = 0x00; + *pos++ = 0x00; + + buf += 3; + continue; + } + *pos++ = *buf++; + } + + *len_ret = pos - *ret; +} + +/*uint32_t read_bits(struct buf_reader *buf, int len) +{ + uint32_t bits = 0x00; + int i, j; + for(i=0, j=0; i<len; i++) { + while(buf->cur_offset >= 8) { + buf->cur_pos++; + buf->cur_offset -= 8; + } + uint8_t bit = (*buf->cur_pos >> (7 - buf->cur_offset)) & 0x01; + bits |= ((uint32_t)bit) << i; + buf->cur_offset++; + } +printf("ret: 0x%08x\n", bits); + return bits; +}*/ + +static inline uint32_t read_bits (struct buf_reader *buf, int len) +{ + static uint32_t i_mask[33] = + { 0x00, + 0x01, 0x03, 0x07, 0x0f, + 0x1f, 0x3f, 0x7f, 0xff, + 0x1ff, 0x3ff, 0x7ff, 0xfff, + 0x1fff, 0x3fff, 0x7fff, 0xffff, + 0x1ffff, 0x3ffff, 0x7ffff, 0xfffff, + 0x1fffff, 0x3fffff, 0x7fffff, 0xffffff, + 0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff, + 0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff}; + + int i_shr; + uint32_t bits = 0; + + while(len > 0 && (buf->cur_pos - buf->buf) < buf->len) { + if((i_shr = buf->cur_offset-len) >= 0) { + bits |= (*buf->cur_pos >> i_shr)&i_mask[len]; + buf->cur_offset -= len; + if(buf->cur_offset == 0) { + buf->cur_pos++; + buf->cur_offset = 8; + } + return bits; + } else { + bits |= (*buf->cur_pos & i_mask[buf->cur_offset]) << -i_shr; + len -= buf->cur_offset; + buf->cur_pos++; + buf->cur_offset = 8; + } + } + return bits; +} + +uint32_t read_exp_golomb(struct buf_reader *buf) +{ + int leading_zero_bits = 0; + + while(read_bits(buf, 1) == 0 && leading_zero_bits < 32) + leading_zero_bits++; + + uint32_t code = (1<<leading_zero_bits) - 1 + read_bits(buf, leading_zero_bits); + return code; +} + +int32_t read_exp_golomb_s(struct buf_reader *buf) +{ + uint32_t ue = read_exp_golomb(buf); + int32_t code = ue&0x01 ? (ue+1)/2 : -(ue/2); + return code; +} + +int parse_nal_header(struct buf_reader *buf, struct nal_unit *nal) +{ + if(buf->len < 1) + return -1; + int ret = -1; + + nal->nal_ref_idc = (buf->buf[0] >> 5) & 0x03; + nal->nal_unit_type = buf->buf[0] & 0x1f; + + buf->cur_pos = buf->buf + 1; + //printf("NAL: %d\n", nal->nal_unit_type); + + struct buf_reader ibuf; + ibuf.cur_offset = 8; + + switch(nal->nal_unit_type) { + case NAL_SPS: + decode_nal(&ibuf.buf, &ibuf.len, buf->cur_pos, buf->len-1); + ibuf.cur_pos = ibuf.buf; + if(!nal->sps) + nal->sps = malloc(sizeof(struct seq_parameter_set_rbsp)); + else + memset(nal->sps, 0x00, sizeof(struct seq_parameter_set_rbsp)); + + parse_sps(&ibuf, nal->sps); + free(ibuf.buf); + ret = NAL_SPS; + break; + case NAL_PPS: + if(!nal->pps) + nal->pps = malloc(sizeof(struct pic_parameter_set_rbsp)); + else + memset(nal->pps, 0x00, sizeof(struct pic_parameter_set_rbsp)); + + parse_pps(buf, nal->pps); + ret = NAL_PPS; + break; + case NAL_SLICE: + case NAL_PART_A: + case NAL_PART_B: + case NAL_PART_C: + case NAL_SLICE_IDR: + if(nal->sps && nal->pps) { + if(!nal->slc) + nal->slc = malloc(sizeof(struct slice_header)); + else + memset(nal->slc, 0x00, sizeof(struct slice_header)); + + parse_slice_header(buf, nal); + ret = nal->nal_unit_type; + } + break; + default: + ret = nal->nal_unit_type; + break; + } + + return ret; +} + +void skip_scaling_list(struct buf_reader *buf, int size) +{ + int i; + for(i = 0; i < size; i++) { + read_exp_golomb_s(buf); + } +} + +uint8_t parse_sps(struct buf_reader *buf, struct seq_parameter_set_rbsp *sps) +{ + sps->profile_idc = buf->buf[0]; + sps->constraint_setN_flag = (buf->buf[1] >> 4) & 0x0f; + sps->level_idc = buf->buf[2]; + + buf->cur_pos = buf->buf+3; + sps->seq_parameter_set_id = read_exp_golomb(buf); + if(sps->profile_idc == 100 || sps->profile_idc == 110 || + sps->profile_idc == 122 || sps->profile_idc == 144) { + sps->chroma_format_idc = read_exp_golomb(buf); + if(sps->chroma_format_idc == 3) { + sps->residual_colour_transform_flag = read_bits(buf, 1); + } + + sps->bit_depth_luma_minus8 = read_exp_golomb(buf); + sps->bit_depth_chroma_minus8 = read_exp_golomb(buf); + sps->qpprime_y_zero_transform_bypass_flag = read_bits(buf, 1); + sps->seq_scaling_matrix_present_flag = read_bits(buf, 1); + if(sps->seq_scaling_matrix_present_flag) { + sps->seq_scaling_lists_present_flag = read_bits(buf, 8); + int i; + for(i=0; i<8; i++) { + if((sps->seq_scaling_lists_present_flag >> (7-i)) & 0x01) { + // NOTE: just skip the scaling lists, as we do not + // need their data for parsing + if(i<6) + skip_scaling_list(buf, 16); + else + skip_scaling_list(buf, 64); + } + } + } + } + + sps->log2_max_frame_num_minus4 = read_exp_golomb(buf); + + sps->pic_order_cnt_type = read_exp_golomb(buf); + if(!sps->pic_order_cnt_type) + sps->log2_max_pic_order_cnt_lsb_minus4 = read_exp_golomb(buf); + else { + sps->delta_pic_order_always_zero_flag = read_bits(buf, 1); + sps->offset_for_non_ref_pic = read_exp_golomb_s(buf); + sps->offset_for_top_to_bottom_field = read_exp_golomb_s(buf); + sps->num_ref_frames_in_pic_order_cnt_cycle = read_exp_golomb(buf); + int i; + for(i=0; i<sps->num_ref_frames_in_pic_order_cnt_cycle; i++) { + sps->offset_for_ref_frame[i] = read_exp_golomb_s(buf); + } + } + sps->num_ref_frames = read_exp_golomb(buf); + sps->gaps_in_frame_num_value_allowed_flag = read_bits(buf, 1); + + /*sps->pic_width_in_mbs_minus1 = read_exp_golomb(buf); + sps->pic_height_in_map_units_minus1 = read_exp_golomb(buf);*/ + sps->pic_width = 16 * (read_exp_golomb(buf) + 1); + sps->pic_height = 16 * (read_exp_golomb(buf) + 1); + + sps->frame_mbs_only_flag = read_bits(buf, 1); + + /* compute the height correctly even for interlaced material */ + sps->pic_height = (2-sps->frame_mbs_only_flag) * sps->pic_height; + //printf("res: %dx%d\n", sps->pic_width, sps->pic_height); + + if(!sps->frame_mbs_only_flag) + sps->mb_adaptive_frame_field_flag = read_bits(buf, 1); + + sps->direct_8x8_inference_flag = read_bits(buf, 1); + sps->frame_cropping_flag = read_bits(buf, 1); + if(sps->frame_cropping_flag) { + sps->frame_crop_left_offset = read_exp_golomb(buf); + sps->frame_crop_right_offset = read_exp_golomb(buf); + sps->frame_crop_top_offset = read_exp_golomb(buf); + sps->frame_crop_bottom_offset = read_exp_golomb(buf); + } + sps->vui_parameters_present_flag = read_bits(buf, 1); + /*if(sps->vui_parameters_present_flag) + printf("ERROR: vui_parameters is not implemented\n");*/ + + return 0; +} + +uint8_t parse_pps(struct buf_reader *buf, struct pic_parameter_set_rbsp *pps) +{ + pps->pic_parameter_set_id = read_exp_golomb(buf); + pps->seq_parameter_set_id = read_exp_golomb(buf); + pps->entropy_coding_mode_flag = read_bits(buf, 1); + pps->pic_order_present_flag = read_bits(buf, 1); + return 0; +} + +uint8_t parse_slice_header(struct buf_reader *buf, struct nal_unit *nal) +{ + struct seq_parameter_set_rbsp *sps = nal->sps; + struct pic_parameter_set_rbsp *pps = nal->pps; + struct slice_header *slc = nal->slc; + if(!sps || !pps) + return -1; + + slc->first_mb_in_slice = read_exp_golomb(buf); + slc->slice_type = read_exp_golomb(buf); + slc->pic_parameter_set_id = read_exp_golomb(buf); + slc->frame_num = read_bits(buf, sps->log2_max_frame_num_minus4 + 4); + if(!sps->frame_mbs_only_flag) { + slc->field_pic_flag = read_bits(buf, 1); + if(slc->field_pic_flag) + slc->bottom_field_flag = read_bits(buf, 1); + else + slc->bottom_field_flag = -1; + } else { + slc->field_pic_flag = 0; + slc->bottom_field_flag = -1; + } + + if(nal->nal_unit_type == NAL_SLICE_IDR) + slc->idr_pic_id = read_exp_golomb(buf); + + if(!sps->pic_order_cnt_type) { + slc->pic_order_cnt_lsb = read_bits(buf, sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + if(pps->pic_order_present_flag && !slc->field_pic_flag) + slc->delta_pic_order_cnt_bottom = read_exp_golomb_s(buf); + } else if (sps->pic_order_cnt_type == 1) { + slc->delta_pic_order_cnt[0] = read_exp_golomb_s(buf); + if(pps->pic_order_present_flag && !slc->field_pic_flag) + slc->delta_pic_order_cnt[1] = read_exp_golomb_s(buf); + } + /* do not need more information for packetizing */ + + return 0; +} + + + +/* ----------------- NAL parser ----------------- */ + +struct nal_parser* init_parser() +{ + struct nal_parser *parser = malloc(sizeof(struct nal_parser)); + memset(parser->buf, 0x00, MAX_FRAME_SIZE); + parser->buf_len = 0; + parser->found_sps = 0; + parser->found_pps = 0; + parser->nal0 = malloc(sizeof(struct nal_unit)); + memset(parser->nal0, 0x00, sizeof(struct nal_unit)); + parser->nal1 = malloc(sizeof(struct nal_unit)); + memset(parser->nal1, 0x00, sizeof(struct nal_unit)); + parser->current_nal = parser->nal0; + parser->last_nal = parser->nal1; + + parser->last_nal_res = 0; + parser->slice = 0; + parser->field = -1; + parser->have_top = 0; + + return parser; +} + +void free_parser(struct nal_parser *parser) +{ + free(parser->nal0); + free(parser->nal1); + free(parser); +} + +int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, + uint8_t **ret_buf, int *ret_len) +{ + int next_nal; + int parsed_len = 0; + int search_offset = 0; + + while((next_nal = seek_for_nal(inbuf+search_offset, inbuf_len-parsed_len)) >= 0) { + // save buffer up to the nal-start + if(parser->buf_len + next_nal + search_offset > MAX_FRAME_SIZE) { + printf("buf underrun!!\n"); + *ret_len = 0; + *ret_buf = NULL; + return parsed_len; + } + //if(parser->last_nal_res != 1) { + xine_fast_memcpy(&parser->buf[parser->buf_len], inbuf, next_nal+search_offset); + parser->buf_len += next_nal+search_offset; + //} + inbuf += next_nal+search_offset; + parsed_len += next_nal+search_offset; + + if((parser->last_nal_res = parse_nal(inbuf+4, inbuf_len-parsed_len, parser)) == 1 + && parser->buf_len>0) { + // parse_nal returned 1 --> detected a frame_boundary + *ret_buf = malloc(parser->buf_len); + xine_fast_memcpy(*ret_buf, parser->buf, parser->buf_len); + *ret_len = parser->buf_len; + + //memset(parser->buf, 0x00, parser->buf_len); + parser->buf_len = 0; + parser->last_nal_res = 0; + return parsed_len; + } + + search_offset = 4; + } + + // no further NAL found, copy the rest of the stream + // into the buffer +// if(parser->last_nal_res != 1) { + xine_fast_memcpy(&parser->buf[parser->buf_len], inbuf, inbuf_len-parsed_len); + parser->buf_len += inbuf_len-parsed_len; +// } + + parsed_len += (inbuf_len-parsed_len); + *ret_len = 0; + *ret_buf = NULL; + + return parsed_len; +} + +int parse_nal(uint8_t *buf, int buf_len, struct nal_parser *parser) +{ + struct buf_reader bufr; + + bufr.buf = buf; + bufr.cur_pos = buf; + bufr.cur_offset = 8; + bufr.len = buf_len; + + struct nal_unit *nal = parser->current_nal; + struct nal_unit *last_nal = parser->last_nal; + + int res = parse_nal_header(&bufr, nal); + + if(res >= NAL_SLICE && res <= NAL_SLICE_IDR) { + // now detect if it's a new frame! + int ret = 0; + if(nal->slc->field_pic_flag == 1) + parser->field = nal->slc->bottom_field_flag; + else { + parser->have_top = 1; + parser->field = -1; + } + + if(nal->slc->field_pic_flag == 1 && nal->slc->bottom_field_flag == 0) + parser->have_top = 1; + + parser->slice = 1; + + if(nal->slc == NULL || last_nal->slc == NULL) { + ret = 1; + } + if(nal->slc && last_nal->slc && + (nal->slc->frame_num != last_nal->slc->frame_num)) { + ret = 1; + } + if(nal->slc && last_nal->slc && + (nal->slc->pic_parameter_set_id != last_nal->slc->pic_parameter_set_id)) { + ret = 1; + } + if(nal->slc && last_nal->slc && + (nal->slc->field_pic_flag != last_nal->slc->field_pic_flag)) { + ret = 1; + } + if(nal->slc && last_nal->slc && + (nal->slc->bottom_field_flag != -1 && + last_nal->slc->bottom_field_flag != -1 && + nal->slc->bottom_field_flag != last_nal->slc->bottom_field_flag)) { + ret = 1; + } + if(nal->nal_ref_idc != last_nal->nal_ref_idc && + (nal->nal_ref_idc == 0 || last_nal->nal_ref_idc == 0)) { + ret = 1; + } + if(nal->sps && nal->slc && last_nal->slc && + (nal->sps->pic_order_cnt_type == 0 && + (nal->slc->pic_order_cnt_lsb != last_nal->slc->pic_order_cnt_lsb || + nal->slc->delta_pic_order_cnt_bottom != last_nal->slc->delta_pic_order_cnt_bottom))) { + ret = 1; + } + if(nal->slc && last_nal->slc && + (nal->sps->pic_order_cnt_type == 1 && + (nal->slc->delta_pic_order_cnt[0] != last_nal->slc->delta_pic_order_cnt[0] || + nal->slc->delta_pic_order_cnt[1] != last_nal->slc->delta_pic_order_cnt[1]))) { + ret = 1; + } + if(nal->nal_unit_type != last_nal->nal_unit_type && + (nal->nal_unit_type == 5 || last_nal->nal_unit_type == 5)) { + ret = 1; + } + if(nal->slc && last_nal->slc && + (nal->nal_unit_type == 5 && last_nal->nal_unit_type == 5 && + nal->slc->idr_pic_id != last_nal->slc->idr_pic_id)) { + ret = 1; + } + + if(parser->current_nal == parser->nal0) { + parser->current_nal = parser->nal1; + parser->last_nal = parser->nal0; + } + else { + parser->current_nal = parser->nal0; + parser->last_nal = parser->nal1; + } + if(parser->current_nal->sps == NULL) + parser->current_nal->sps = parser->last_nal->sps; + if(parser->current_nal->pps == NULL) + parser->current_nal->pps = parser->last_nal->pps; + + /*if(ret) + parser->slice = 0;*/ + /*if(parser->slice && parser->have_top && parser->field != 0) { + parser->have_frame = 1; + parser->have_top = 0; + parser->slice = 0; + return ret; + }*/ + return 0; + } else if(res == NAL_PPS || res == NAL_SPS) { + return 1; + } else if (res == NAL_AU_DELIMITER || res == NAL_SEI || + (res >= 13 && res <= 18)) { + //printf("New Frame\n"); + return 1; + } + + return 0; +} + +int seek_for_nal(uint8_t *buf, int buf_len) +{ + int i; + for(i=0; i<buf_len-3; i++) { + if(buf[i] == 0x00 && buf[i+1] == 0x00 && + buf[i+2] == 0x00 && buf[i+3] == 0x01) { + //printf("found nal at: %d\n", i); + return i; + } + } + + return -1; +} diff -r 66e1654718fb src/libxinevdec/nal_parser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libxinevdec/nal_parser.h Tue Jun 24 14:06:43 2008 -0700 @@ -0,0 +1,141 @@ +#ifndef NAL_PARSER_H_ +#define NAL_PARSER_H_ + +#include <stdlib.h> + +#include "xine_internal.h" + +enum nal_unit_types { + NAL_UNSPECIFIED = 0, + NAL_SLICE, + NAL_PART_A, + NAL_PART_B, + NAL_PART_C, + NAL_SLICE_IDR, + NAL_SEI, + NAL_SPS, + NAL_PPS, + NAL_AU_DELIMITER, + NAL_END_OF_SEQUENCE, + NAL_END_OF_STREAM, + NAL_FILLER_DATA, + NAL_SPS_EXT +}; + + + +struct nal_unit { + uint8_t nal_ref_idc; // 0x03 + uint8_t nal_unit_type; // 0x1f + + struct seq_parameter_set_rbsp *sps; + struct pic_parameter_set_rbsp *pps; + struct slice_header *slc; +}; + +struct seq_parameter_set_rbsp { + uint8_t profile_idc; // 0xff + uint8_t constraint_setN_flag; // 0x0f + uint8_t level_idc; // 0xff + uint32_t seq_parameter_set_id; + uint32_t chroma_format_idc; + uint8_t residual_colour_transform_flag; // 0x01 + uint32_t bit_depth_luma_minus8; + uint32_t bit_depth_chroma_minus8; + uint8_t qpprime_y_zero_transform_bypass_flag; + uint8_t seq_scaling_matrix_present_flag; + uint8_t seq_scaling_lists_present_flag; // each bit = 1 list flag + // TODO: here would be the scaling lists... + uint32_t log2_max_frame_num_minus4; + uint32_t pic_order_cnt_type; + // if pic_order_cnt_type==0 + uint32_t log2_max_pic_order_cnt_lsb_minus4; + // else + uint8_t delta_pic_order_always_zero_flag; + int32_t offset_for_non_ref_pic; + int32_t offset_for_top_to_bottom_field; + uint8_t num_ref_frames_in_pic_order_cnt_cycle; + int32_t offset_for_ref_frame[256]; + // TODO: some more ignored here + uint32_t num_ref_frames; + uint8_t gaps_in_frame_num_value_allowed_flag; + /*uint32_t pic_width_in_mbs_minus1; + uint32_t pic_height_in_map_units_minus1;*/ + uint32_t pic_width; + uint32_t pic_height; + uint8_t frame_mbs_only_flag; + uint8_t mb_adaptive_frame_field_flag; + uint8_t direct_8x8_inference_flag; + uint8_t frame_cropping_flag; + uint32_t frame_crop_left_offset; + uint32_t frame_crop_right_offset; + uint32_t frame_crop_top_offset; + uint32_t frame_crop_bottom_offset; + uint8_t vui_parameters_present_flag; + // TODO: add vui_parameters, rtbsp_trailing_bits + +}; + +struct pic_parameter_set_rbsp { + uint32_t pic_parameter_set_id; + uint32_t seq_parameter_set_id; + uint8_t entropy_coding_mode_flag; + uint8_t pic_order_present_flag; + + /* we ignore further data, because it's not needed + for packetization */ +}; + +struct slice_header { + uint32_t first_mb_in_slice; + uint32_t slice_type; + uint32_t pic_parameter_set_id; + uint32_t frame_num; + int8_t field_pic_flag; + int8_t bottom_field_flag; + uint32_t idr_pic_id; + + /* sps->pic_order_cnt_type == 0 */ + uint32_t pic_order_cnt_lsb; + int32_t delta_pic_order_cnt_bottom; + /* sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag */ + int32_t delta_pic_order_cnt[2]; + + /* not needed for packetizing */ + /*int32_t redundant_pic_cnt; + uint8_t direct_spatial_mv_pred_flag; + uint8_t num_ref_idx_active_override_flag; + uint32_t num_ref_idx_l0_active_minus1; + uint32_t num_ref_idx_l1_active_minus1;*/ + +}; + + +#define MAX_FRAME_SIZE 1024*1024 + +struct nal_parser { + uint8_t buf[MAX_FRAME_SIZE]; + int buf_len; + int found_sps; + int found_pps; + int last_nal_res; + int field; // 0=top, 1=bottom, -1=both + int slice; + int have_top; + int have_frame; + struct nal_unit *nal0; + struct nal_unit *nal1; + struct nal_unit *current_nal; + struct nal_unit *last_nal; +}; + +int parse_nal(uint8_t *buf, int buf_len, struct nal_parser *parser); + +int seek_for_nal(uint8_t *buf, int buf_len); + +struct nal_parser* init_parser(); +void free_parser(struct nal_parser *parser); +int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, + uint8_t **ret_buf, int *ret_len); + +#endif ------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://sourceforge.net/services/buy/index.php _______________________________________________ xine-devel mailing list xine-devel@... https://lists.sourceforge.net/lists/listinfo/xine-devel |
|
|
Re: PATCH: Add support for CoreAVC via dshowserverOn Tue, 2008-06-24 at 14:19 -0700, Alan Nisota wrote:
> I was asked to send this patch to xine-devel by Darren Salt. > > It implements support for communicating with the dshowserver > (coreavc-for-linux.googlecode.com) > This is mainly useful for using CoreAVC in Linux (a very fast H264 > decoder), however it could be made to work with other win32 codecs. Does dshowserver support the "other" Win32 DLLs? ------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://sourceforge.net/services/buy/index.php _______________________________________________ xine-devel mailing list xine-devel@... https://lists.sourceforge.net/lists/listinfo/xine-devel |
|
|
Re: PATCH: Add support for CoreAVC via dshowserverI demand that Alan Nisota may or may not have written...
> I was asked to send this patch to xine-devel by Darren Salt. [snip] > I have addressed many of the issues he requested I address except for: > * The plugin description should be translatable (use N_() for this) > I don't see any examples of other plugins doing this, so I wasn't sure > how to proceed. That's really 1.2-only, but I see no harm in doing that in 1.1 as well. > * Documentation patches > I have no idea what he wanted here. Adding and/or modifying files in doc and possibly doc/faq. (A separate patch for this is fine.) > * Fixed-size buffers should be avoided wherever practical, e.g. use > asprintf() where it makes sense to do so. > I did move the constant-sized strings (snprintf) to use asprintf as > requested, but this really didn't feel like the right thing to do to me. A fixed-size buffer is fine if you can be sure that it'll never be overflowed... It occurs to me, however, that being able to configure the location of dshowserver might be useful (with the default determined automatically on first run, if it's not configured at build time). [snip] -- | Darren Salt | linux or ds at | nr. Ashington, | Toon | RISC OS, Linux | youmustbejoking,demon,co,uk | Northumberland | Army | + Use more efficient products. Use less. BE MORE ENERGY EFFICIENT. The soul would have no rainbow had the eyes no tears. ------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://sourceforge.net/services/buy/index.php _______________________________________________ xine-devel mailing list xine-devel@... https://lists.sourceforge.net/lists/listinfo/xine-devel |
|
|
Re: PATCH: Add support for CoreAVC via dshowserver> > * Documentation patches
> > I have no idea what he wanted here. > > Adding and/or modifying files in doc and possibly doc/faq. (A separate patch > for this is fine.) I think your wiki has very useful information for doc/faq I propose to discuss the issues with xine and this dshowserver patch in xine-user mail list. I already have sent here my bug report :) > > > * Fixed-size buffers should be avoided wherever practical, e.g. use > > asprintf() where it makes sense to do so. > > I did move the constant-sized strings (snprintf) to use asprintf as > > requested, but this really didn't feel like the right thing to do to me. > > A fixed-size buffer is fine if you can be sure that it'll never be > overflowed... > > It occurs to me, however, that being able to configure the location of > dshowserver might be useful (with the default determined automatically on > first run, if it's not configured at build time). > > [snip] ------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://sourceforge.net/services/buy/index.php _______________________________________________ xine-devel mailing list xine-devel@... https://lists.sourceforge.net/lists/listinfo/xine-devel |
|
|
Re: PATCH: Add support for CoreAVC via dshowserverfrom coreavc-for-linux@...
Дата: Thu, 26 Jun 2008 09:58:53 +0100 От: Morfsta <morfsta@...> Кому: alannisota@... Копия: coreavc-for-linux@... Тема: CoreAVC Patch for xine Hi Alan, Thanks for continuing to work on the CoreAVC patch for xine. One thing I have noticed is that your aspect ratio setting (this->ratio), I think, is incorrect. You always seem to set it to the same value based on the width and height of the channel which is: this->ratio = (double)this->width/(double)this->height; Ideally, this should come from the stream and can be found in the SPS. In my dirty xine-lib-1.2 patch the following code worked in the NAL/SPS parser: - + if (br_get_bit(&br)) { /* VUI parameters */ + if (br_get_bit(&br)) { /* Aspect Info */ + uint32_t aspect_ratio_idc = br_get_u8(&br); + printf("H.264 SPS: -> Aspect Ratio IDC %d\n", aspect_ratio_idc); + const uint32_t Extended_SAR = 255; + if (aspect_ratio_idc == Extended_SAR) { + uint32_t sar_width = br_get_u16(&br); + uint32_t sar_height = br_get_u16(&br); + sps->ratio = (float) sar_width / sar_height; + sps->ratio = (float) ( (float) sar_width / sar_height ) * ( (float) sps->width / sps->height ) ; + printf("H.264 SPS: -> SAR_Size = %dx%d\n", sar_width, sar_height); + printf("H.264 SPS: -> Ratio = %f\n", sps->ratio); + } else { + AVRational sar = pixel_aspect[aspect_ratio_idc]; + printf("H.264 SPS: -> Pixel Aspect = %d / %d\n", sar.num, sar.den); + sps->ratio = (float) ( (float) sar.num / sar.den ) * ( (float) sps->width / sps->height ) ; + printf("H.264 SPS: -> Ratio = %f\n", sps->ratio); + } + } + } Of course you can then copy sps->ratio to this->ratio. Also, is there a CHANGELOG or any way of tracking updates to your patch? I don't know yet if all the debugging and core information I sent you awhile ago was used or whether any changes have been made. Hope this helps, Kind Regards, Morfsta ------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://sourceforge.net/services/buy/index.php _______________________________________________ xine-devel mailing list xine-devel@... https://lists.sourceforge.net/lists/listinfo/xine-devel |
| Free embeddable forum powered by Nabble | Forum Help |