summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuenter Bartsch <guenter@users.sourceforge.net>2002-08-19 17:40:41 +0000
committerGuenter Bartsch <guenter@users.sourceforge.net>2002-08-19 17:40:41 +0000
commitebcf2908e18aae2b2638b97356c65474e5b33db4 (patch)
tree3b1b072d56764398040ba512d1853820e9f1ab3b
parent241b8b70a1055a726d07dc379d36f527d2d655c5 (diff)
downloadxine-lib-ebcf2908e18aae2b2638b97356c65474e5b33db4.tar.gz
xine-lib-ebcf2908e18aae2b2638b97356c65474e5b33db4.tar.bz2
try to make ffmpeg handle mpeg streams, try to handle buffers that contain more than one frame
CVS patchset: 2486 CVS date: 2002/08/19 17:40:41
-rw-r--r--src/libffmpeg/xine_decoder.c448
1 files changed, 333 insertions, 115 deletions
diff --git a/src/libffmpeg/xine_decoder.c b/src/libffmpeg/xine_decoder.c
index 89c446231..470cba149 100644
--- a/src/libffmpeg/xine_decoder.c
+++ b/src/libffmpeg/xine_decoder.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: xine_decoder.c,v 1.50 2002/07/30 20:13:09 miguelfreitas Exp $
+ * $Id: xine_decoder.c,v 1.51 2002/08/19 17:40:41 guenter Exp $
*
* xine decoder plugin using ffmpeg
*
@@ -46,9 +46,12 @@
#define LOG
*/
+#define SLICE_BUFFER_SIZE (1194 * 1024)
+
typedef struct ff_decoder_s {
video_decoder_t video_decoder;
+ xine_t *xine;
vo_instance_t *video_out;
int video_step;
int decoder_ok;
@@ -62,6 +65,16 @@ typedef struct ff_decoder_s {
AVPicture av_picture;
AVCodecContext context;
+
+ /* mpeg sequence header parsing, stolen from libmpeg2 */
+
+ uint32_t shift;
+ uint8_t *chunk_buffer;
+ uint8_t *chunk_ptr;
+ uint8_t code;
+
+ int is_continous;
+
} ff_decoder_t;
#define VIDEOBUFSIZE 128*1024
@@ -82,7 +95,175 @@ static int ff_can_handle (video_decoder_t *this_gen, int buf_type) {
buf_type == BUF_VIDEO_RV10 ||
/* PIX_FMT_YUV410P must be supported to enable svq1 */
/* buf_type == BUF_VIDEO_SORENSON_V1 || */
- buf_type == BUF_VIDEO_JPEG);
+ buf_type == BUF_VIDEO_JPEG ||
+ buf_type == BUF_VIDEO_MPEG);
+}
+
+static void init_codec (ff_decoder_t *this, AVCodec *codec) {
+
+ /* force (width % 8 == 0), otherwise there will be
+ * display problems with Xv.
+ */
+ this->bih.biWidth = (this->bih.biWidth + 7) & (~7);
+
+ memset(&this->context, 0, sizeof(this->context));
+ this->context.width = this->bih.biWidth;
+ this->context.height = this->bih.biHeight;
+
+ if (avcodec_open (&this->context, codec) < 0) {
+ printf ("ffmpeg: couldn't open decoder\n");
+ return;
+ }
+
+ this->decoder_ok = 1;
+ this->video_out->open (this->video_out);
+
+ /* needed to play streams generated by MS ISO MPEG4 codec.
+ Michael Niedermayer explained:
+ M$ "ISO MPEG4" uses illegal vlc code combinations, a ISO MPEG4 compliant
+ decoder which support error resilience should handle them like errors.
+ */
+ if (this->illegal_vlc)
+ this->context.error_resilience=-1;
+
+ if (this->buf)
+ free (this->buf);
+
+ this->buf = xine_xmalloc (VIDEOBUFSIZE);
+ this->bufsize = VIDEOBUFSIZE;
+
+ this->skipframes = 0;
+}
+
+static void find_sequence_header (ff_decoder_t *this,
+ uint8_t * current, uint8_t * end){
+
+ uint8_t code;
+
+ if (this->decoder_ok)
+ return;
+
+ while (current != end) {
+
+ uint32_t shift;
+ uint8_t *chunk_ptr;
+ uint8_t *limit;
+ uint8_t byte;
+
+ code = this->code;
+
+ /* copy chunk */
+
+ shift = this->shift;
+ chunk_ptr = this->chunk_ptr;
+ limit = current + (this->chunk_buffer + SLICE_BUFFER_SIZE - chunk_ptr);
+ if (limit > end)
+ limit = end;
+
+ while (1) {
+
+ byte = *current++;
+ if (shift != 0x00000100) {
+ shift = (shift | byte) << 8;
+ *chunk_ptr++ = byte;
+ if (current < limit)
+ continue;
+ if (current == end) {
+ this->chunk_ptr = chunk_ptr;
+ this->shift = shift;
+ current = 0;
+ break;
+ } else {
+ /* we filled the chunk buffer without finding a start code */
+ this->code = 0xb4; /* sequence_error_code */
+ this->chunk_ptr = this->chunk_buffer;
+ break;
+ }
+ }
+ this->code = byte;
+ this->chunk_ptr = this->chunk_buffer;
+ this->shift = 0xffffff00;
+ break;
+ }
+
+ if (current == NULL)
+ return ;
+
+#ifdef LOG
+ printf ("ffmpeg: looking for sequence header... %02x\n", code);
+#endif
+
+ /* mpeg2_stats (code, this->chunk_buffer); */
+
+ if (code == 0xb3) { /* sequence_header_code */
+
+ AVCodec *codec = NULL;
+ int width, height, frame_rate_code;
+
+#ifdef LOG
+ printf ("ffmpeg: found sequence header !\n");
+#endif
+
+ height = (this->chunk_buffer[0] << 16) | (this->chunk_buffer[1] << 8)
+ | this->chunk_buffer[2];
+
+ width = ((height >> 12) + 15) & ~15;
+ height = ((height & 0xfff) + 15) & ~15;
+
+ xine_log (this->xine, XINE_LOG_FORMAT,
+ "ffmpeg: frame size is %d x %d\n",
+ width, height);
+
+ this->bih.biWidth = width;
+ this->bih.biHeight = height;
+
+ frame_rate_code = this->chunk_buffer[3] & 15;
+
+ switch (frame_rate_code) {
+ case 1: /* 23.976 fps */
+ this->video_step = 3913;
+ break;
+ case 2: /* 24 fps */
+ this->video_step = 3750;
+ break;
+ case 3: /* 25 fps */
+ this->video_step = 3600;
+ break;
+ case 4: /* 29.97 fps */
+ this->video_step = 3003;
+ break;
+ case 5: /* 30 fps */
+ this->video_step = 3000;
+ break;
+ case 6: /* 50 fps */
+ this->video_step = 1800;
+ break;
+ case 7: /* 59.94 fps */
+ this->video_step = 1525;
+ break;
+ case 8: /* 60 fps */
+ this->video_step = 1509;
+ break;
+ default:
+ printf ("ffmpeg: invalid/unknown frame rate code : %d \n",
+ frame_rate_code);
+ this->video_step = 3000;
+ }
+
+ /*
+ * init codec
+ */
+
+ codec = avcodec_find_decoder (CODEC_ID_MPEG1VIDEO);
+ if (!codec) {
+ printf ("avcodec_find_decoder (CODEC_ID_MPEG1VIDEO) failed.\n");
+ abort();
+ }
+
+ this->is_continous = 1;
+ init_codec (this, codec);
+ }
+ }
}
static void ff_init (video_decoder_t *this_gen, vo_instance_t *video_out) {
@@ -92,6 +273,12 @@ static void ff_init (video_decoder_t *this_gen, vo_instance_t *video_out) {
this->video_out = video_out;
this->decoder_ok = 0;
this->buf = NULL;
+
+ this->shift = 0xffffff00;
+ this->code = 0xb4;
+ this->chunk_ptr = this->chunk_buffer;
+
+ this->is_continous = 0;
}
static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
@@ -103,8 +290,12 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
buf->type, buf, buf->decoder_flags);
#endif
- if (buf->decoder_flags & BUF_FLAG_PREVIEW)
+ if (buf->decoder_flags & BUF_FLAG_PREVIEW) {
+ if ( (buf->type & 0xFFFF0000) == BUF_VIDEO_MPEG ) {
+ find_sequence_header (this, buf->content, buf->content+buf->size);
+ }
return;
+ }
if (buf->decoder_flags & BUF_FLAG_HEADER) {
@@ -194,7 +385,6 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
this->buf = malloc( VIDEOBUFSIZE );
this->bufsize = VIDEOBUFSIZE;
- this->size = 0;
this->skipframes = 0;
@@ -214,138 +404,165 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
if (buf->decoder_flags & BUF_FLAG_FRAMERATE)
this->video_step = buf->decoder_info[0];
- if (buf->decoder_flags & BUF_FLAG_FRAME_END) {
+ if ( (buf->decoder_flags & BUF_FLAG_FRAME_END) || this->is_continous) {
vo_frame_t *img;
int got_picture, len, y;
uint8_t *dy, *du, *dv, *sy, *su, *sv;
+ int offset;
- /* decode video frame */
+ /* decode video frame(s) */
/* skip decoding b frames if too late */
this->context.hurry_up = (this->skipframes > 2) ? 1:0;
- len = avcodec_decode_video (&this->context, &this->av_picture,
- &got_picture, this->buf,
- this->size);
-#ifdef ARCH_X86
- emms_c ();
+ offset = 0;
+ while (this->size>0) {
+ len = avcodec_decode_video (&this->context, &this->av_picture,
+ &got_picture, &this->buf[offset],
+ this->size);
+ if (len<0) {
+ printf ("ffmpeg: error decompressing frame\n");
+ this->size=0;
+ return;
+ }
+
+ this->size -= len;
+ offset += len;
+
+ if (!got_picture) {
+ printf ("ffmpeg: didn't get a picture, got %d bytes left\n",
+ this->size);
+
+ if (this->size>0)
+ memmove (this->buf, &this->buf[offset], this->size);
+
+ return;
+ }
+
+#ifdef LOG
+ printf ("ffmpeg: got a picture\n");
#endif
- switch(this->context.aspect_ratio_info) {
- case FF_ASPECT_SQUARE:
- ratio = XINE_ASPECT_RATIO_SQUARE;
- break;
- case FF_ASPECT_4_3_625:
- case FF_ASPECT_4_3_525:
- ratio = XINE_ASPECT_RATIO_4_3;
- break;
- case FF_ASPECT_16_9_625:
- case FF_ASPECT_16_9_525:
- ratio = XINE_ASPECT_RATIO_ANAMORPHIC;
- break;
- default:
- ratio = XINE_ASPECT_RATIO_DONT_TOUCH;
- }
+#ifdef ARCH_X86
+ emms_c ();
+#endif
- img = this->video_out->get_frame (this->video_out,
- /* this->av_picture.linesize[0], */
- this->bih.biWidth,
- this->bih.biHeight,
- ratio,
- IMGFMT_YV12,
- VO_BOTH_FIELDS);
-
- img->pts = buf->pts;
- img->duration = this->video_step;
- if (len<0 || this->skipframes) {
- if( !this->skipframes )
- printf ("ffmpeg: error decompressing frame\n");
- img->bad_frame = 1;
- } else {
- img->bad_frame = 0;
-
- dy = img->base[0];
- du = img->base[1];
- dv = img->base[2];
- sy = this->av_picture.data[0];
- su = this->av_picture.data[1];
- sv = this->av_picture.data[2];
-
- for (y=0; y<this->bih.biHeight; y++) {
+ switch(this->context.aspect_ratio_info) {
+ case FF_ASPECT_SQUARE:
+ ratio = XINE_ASPECT_RATIO_SQUARE;
+ break;
+ case FF_ASPECT_4_3_625:
+ case FF_ASPECT_4_3_525:
+ ratio = XINE_ASPECT_RATIO_4_3;
+ break;
+ case FF_ASPECT_16_9_625:
+ case FF_ASPECT_16_9_525:
+ ratio = XINE_ASPECT_RATIO_ANAMORPHIC;
+ break;
+ default:
+ ratio = XINE_ASPECT_RATIO_DONT_TOUCH;
+ }
+
+ img = this->video_out->get_frame (this->video_out,
+ /* this->av_picture.linesize[0], */
+ this->bih.biWidth,
+ this->bih.biHeight,
+ ratio,
+ IMGFMT_YV12,
+ VO_BOTH_FIELDS);
+
+ img->pts = buf->pts;
+ buf->pts = 0;
+ img->duration = this->video_step;
+ if (len<0 || this->skipframes) {
+ if( !this->skipframes )
+ printf ("ffmpeg: error decompressing frame\n");
+ img->bad_frame = 1;
+ } else {
+ img->bad_frame = 0;
- xine_fast_memcpy (dy, sy, this->bih.biWidth);
+ dy = img->base[0];
+ du = img->base[1];
+ dv = img->base[2];
+ sy = this->av_picture.data[0];
+ su = this->av_picture.data[1];
+ sv = this->av_picture.data[2];
- dy += img->pitches[0];
+ for (y=0; y<this->bih.biHeight; y++) {
+
+ xine_fast_memcpy (dy, sy, this->bih.biWidth);
+
+ dy += img->pitches[0];
- sy += this->av_picture.linesize[0];
- }
+ sy += this->av_picture.linesize[0];
+ }
- for (y=0; y<(this->bih.biHeight/2); y++) {
-
- if (this->context.pix_fmt != PIX_FMT_YUV444P) {
-
- xine_fast_memcpy (du, su, this->bih.biWidth/2);
- xine_fast_memcpy (dv, sv, this->bih.biWidth/2);
-
- } else {
-
- int x;
- uint8_t *src;
- uint8_t *dst;
+ for (y=0; y<(this->bih.biHeight/2); y++) {
- /* subsample */
-
- src = su; dst = du;
- for (x=0; x<(this->bih.biWidth/2); x++) {
- *dst = *src;
- dst++;
- src += 2;
- }
- src = sv; dst = dv;
- for (x=0; x<(this->bih.biWidth/2); x++) {
- *dst = *src;
- dst++;
- src += 2;
+ if (this->context.pix_fmt != PIX_FMT_YUV444P) {
+
+ xine_fast_memcpy (du, su, this->bih.biWidth/2);
+ xine_fast_memcpy (dv, sv, this->bih.biWidth/2);
+
+ } else {
+
+ int x;
+ uint8_t *src;
+ uint8_t *dst;
+
+ /* subsample */
+
+ src = su; dst = du;
+ for (x=0; x<(this->bih.biWidth/2); x++) {
+ *dst = *src;
+ dst++;
+ src += 2;
+ }
+ src = sv; dst = dv;
+ for (x=0; x<(this->bih.biWidth/2); x++) {
+ *dst = *src;
+ dst++;
+ src += 2;
+ }
+
}
-
- }
-
- du += img->pitches[1];
- dv += img->pitches[2];
- if (this->context.pix_fmt != PIX_FMT_YUV420P) {
- su += 2*this->av_picture.linesize[1];
- sv += 2*this->av_picture.linesize[2];
- } else {
- su += this->av_picture.linesize[1];
- sv += this->av_picture.linesize[2];
+ du += img->pitches[1];
+ dv += img->pitches[2];
+
+ if (this->context.pix_fmt != PIX_FMT_YUV420P) {
+ su += 2*this->av_picture.linesize[1];
+ sv += 2*this->av_picture.linesize[2];
+ } else {
+ su += this->av_picture.linesize[1];
+ sv += this->av_picture.linesize[2];
+ }
}
- }
- if (img->copy) {
- int height = img->height;
- uint8_t *src[3];
-
- src[0] = img->base[0];
- src[1] = img->base[1];
- src[2] = img->base[2];
-
- while ((height -= 16) >= 0) {
- img->copy(img, src);
- src[0] += 16 * img->pitches[0];
- src[1] += 8 * img->pitches[1];
- src[2] += 8 * img->pitches[2];
+ if (img->copy) {
+ int height = img->height;
+ uint8_t *src[3];
+
+ src[0] = img->base[0];
+ src[1] = img->base[1];
+ src[2] = img->base[2];
+
+ while ((height -= 16) >= 0) {
+ img->copy(img, src);
+ src[0] += 16 * img->pitches[0];
+ src[1] += 8 * img->pitches[1];
+ src[2] += 8 * img->pitches[2];
+ }
}
}
- }
- this->skipframes = img->draw(img);
- if( this->skipframes < 0 )
- this->skipframes = 0;
- img->free(img);
+ this->skipframes = img->draw(img);
+ if( this->skipframes < 0 )
+ this->skipframes = 0;
+ img->free(img);
- this->size = 0;
+ }
}
}
}
@@ -355,10 +572,7 @@ static void ff_flush (video_decoder_t *this_gen) {
}
static void ff_reset (video_decoder_t *this_gen) {
- ff_decoder_t *this = (ff_decoder_t *) this_gen;
-
- /* invalidate buffer on seek */
- this->size = 0;
+ /* seems to handle seeking quite nicelly without any code here */
}
static void ff_close (video_decoder_t *this_gen) {
@@ -441,6 +655,10 @@ video_decoder_t *init_video_decoder_plugin (int iface_version, xine_t *xine) {
this->video_decoder.dispose = ff_dispose;
this->size = 0;
+ this->xine = xine;
+
+ this->chunk_buffer = xine_xmalloc (SLICE_BUFFER_SIZE + 4);
+
this->illegal_vlc = xine->config->register_bool (xine->config, "codec.ffmpeg_illegal_vlc", 1,
_("allow illegal vlc codes in mpeg4 streams"), NULL, NULL, NULL);