static GstFlowReturn gst_mpeg2dec_alloc_buffer (GstMpeg2dec * mpeg2dec, GstVideoCodecFrame * frame, GstBuffer ** buffer) { GstFlowReturn ret; GstVideoFrame vframe; guint8 *buf[3]; ret = gst_mpeg2dec_alloc_sized_buf (mpeg2dec, mpeg2dec->decoded_info.size, frame, buffer); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto beach; if (mpeg2dec->need_cropping && mpeg2dec->has_cropping) { GstVideoCropMeta *crop; GstVideoCodecState *state; GstVideoInfo *vinfo; state = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (mpeg2dec)); vinfo = &state->info; crop = gst_buffer_add_video_crop_meta (frame->output_buffer); /* we can do things slightly more efficient when we know that * downstream understands clipping */ crop->x = 0; crop->y = 0; crop->width = vinfo->width; crop->height = vinfo->height; gst_video_codec_state_unref (state); } if (!gst_video_frame_map (&vframe, &mpeg2dec->decoded_info, *buffer, GST_MAP_READ | GST_MAP_WRITE)) goto map_fail; buf[0] = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0); buf[1] = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 1); buf[2] = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 2); GST_DEBUG_OBJECT (mpeg2dec, "set_buf: %p %p %p, frame %i", buf[0], buf[1], buf[2], frame->system_frame_number); /* Note: We use a non-null 'id' value to make the distinction * between the dummy buffers (which have an id of NULL) and the * ones we did */ mpeg2_set_buf (mpeg2dec->decoder, buf, GINT_TO_POINTER (frame->system_frame_number + 1)); gst_mpeg2dec_save_buffer (mpeg2dec, frame->system_frame_number, &vframe); beach: return ret; map_fail: { GST_ERROR_OBJECT (mpeg2dec, "Failed to map frame"); return GST_FLOW_ERROR; } }
/***************************************************************************** * PutPicture: Put a picture_t in mpeg2 context *****************************************************************************/ static void PutPicture( decoder_t *p_dec, picture_t *p_picture ) { decoder_sys_t *p_sys = p_dec->p_sys; /* */ uint8_t *pp_buf[3]; for( int j = 0; j < 3; j++ ) pp_buf[j] = p_picture ? p_picture->p[j].p_pixels : NULL; mpeg2_set_buf( p_sys->p_mpeg2dec, pp_buf, p_picture ); /* Completly broken API, why the hell does it suppose * the stride of the chroma planes ! */ if( p_picture ) mpeg2_stride( p_sys->p_mpeg2dec, p_picture->p[Y_PLANE].i_pitch ); }
static void sample5 (FILE * mpgfile) { #define BUFFER_SIZE 4096 #define ALIGN_16(p) ((void *)(((uintptr_t)(p) + 15) & ~((uintptr_t)15))) uint8_t buffer[BUFFER_SIZE]; mpeg2dec_t * decoder; const mpeg2_info_t * info; const mpeg2_sequence_t * sequence; mpeg2_state_t state; size_t size; int framenum = 0; int i, j; struct fbuf_s * current_fbuf; decoder = mpeg2_init (); if (decoder == NULL) { fprintf (stderr, "Could not allocate a decoder object.\n"); exit (1); } info = mpeg2_info (decoder); size = (size_t)-1; do { state = mpeg2_parse (decoder); sequence = info->sequence; switch (state) { case STATE_BUFFER: size = fread (buffer, 1, BUFFER_SIZE, mpgfile); mpeg2_buffer (decoder, buffer, buffer + size); break; case STATE_SEQUENCE: mpeg2_custom_fbuf (decoder, 1); for (i = 0; i < 3; i++) { fbuf[i].mbuf[0] = (uint8_t *) malloc (sequence->width * sequence->height + 15); fbuf[i].mbuf[1] = (uint8_t *) malloc (sequence->chroma_width * sequence->chroma_height + 15); fbuf[i].mbuf[2] = (uint8_t *) malloc (sequence->chroma_width * sequence->chroma_height + 15); if (!fbuf[i].mbuf[0] || !fbuf[i].mbuf[1] || !fbuf[i].mbuf[2]) { fprintf (stderr, "Could not allocate an output buffer.\n"); exit (1); } for (j = 0; j < 3; j++) fbuf[i].yuv[j] = ALIGN_16 (fbuf[i].mbuf[j]); fbuf[i].used = 0; } for (i = 0; i < 2; i++) { current_fbuf = get_fbuf (); mpeg2_set_buf (decoder, current_fbuf->yuv, current_fbuf); } break; case STATE_PICTURE: current_fbuf = get_fbuf (); mpeg2_set_buf (decoder, current_fbuf->yuv, current_fbuf); break; case STATE_SLICE: case STATE_END: case STATE_INVALID_END: if (info->display_fbuf) save_pgm (sequence->width, sequence->height, sequence->chroma_width, sequence->chroma_height, info->display_fbuf->buf, framenum++); if (info->discard_fbuf) ((struct fbuf_s *)info->discard_fbuf->id)->used = 0; if (state != STATE_SLICE) for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) free (fbuf[i].mbuf[j]); break; default: break; } } while (size); mpeg2_close (decoder); }
static GstFlowReturn handle_sequence (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info) { GstFlowReturn ret = GST_FLOW_OK; GstClockTime latency; const mpeg2_sequence_t *sequence; GstVideoCodecState *state; GstVideoInfo *dinfo = &mpeg2dec->decoded_info; GstVideoInfo *vinfo; GstVideoFormat format; sequence = info->sequence; if (sequence->frame_period == 0) goto invalid_frame_period; /* mpeg2 video can only be from 16x16 to 4096x4096. Everything * else is a corrupted file */ if (sequence->width > 4096 || sequence->width < 16 || sequence->height > 4096 || sequence->height < 16) goto invalid_size; GST_DEBUG_OBJECT (mpeg2dec, "widthxheight: %dx%d , decoded_widthxheight: %dx%d", sequence->picture_width, sequence->picture_height, sequence->width, sequence->height); if (sequence->picture_width != sequence->width || sequence->picture_height != sequence->height) { GST_DEBUG_OBJECT (mpeg2dec, "we need to crop"); mpeg2dec->need_cropping = TRUE; } else { GST_DEBUG_OBJECT (mpeg2dec, "no cropping needed"); mpeg2dec->need_cropping = FALSE; } /* get subsampling */ if (sequence->chroma_width < sequence->width) { /* horizontally subsampled */ if (sequence->chroma_height < sequence->height) { /* and vertically subsamples */ format = GST_VIDEO_FORMAT_I420; } else { format = GST_VIDEO_FORMAT_Y42B; } } else { /* not subsampled */ format = GST_VIDEO_FORMAT_Y444; } state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (mpeg2dec), format, sequence->picture_width, sequence->picture_height, mpeg2dec->input_state); vinfo = &state->info; /* If we don't have a valid upstream PAR override it */ if (GST_VIDEO_INFO_PAR_N (vinfo) == 1 && GST_VIDEO_INFO_PAR_D (vinfo) == 1 && sequence->pixel_width != 0 && sequence->pixel_height != 0) { #if MPEG2_RELEASE >= MPEG2_VERSION(0,5,0) guint pixel_width, pixel_height; if (mpeg2_guess_aspect (sequence, &pixel_width, &pixel_height)) { vinfo->par_n = pixel_width; vinfo->par_d = pixel_height; } #else vinfo->par_n = sequence->pixel_width; vinfo->par_d = sequence->pixel_height; #endif GST_DEBUG_OBJECT (mpeg2dec, "Setting PAR %d x %d", vinfo->par_n, vinfo->par_d); } vinfo->fps_n = 27000000; vinfo->fps_d = sequence->frame_period; if (!(sequence->flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE)) vinfo->interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED; else vinfo->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; vinfo->chroma_site = GST_VIDEO_CHROMA_SITE_MPEG2; vinfo->colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235; if (sequence->flags & SEQ_FLAG_COLOUR_DESCRIPTION) { /* do color description */ switch (sequence->colour_primaries) { case 1: vinfo->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709; break; case 4: vinfo->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M; break; case 5: vinfo->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG; break; case 6: vinfo->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M; break; case 7: vinfo->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE240M; break; /* 0 forbidden */ /* 2 unspecified */ /* 3 reserved */ /* 8-255 reseved */ default: vinfo->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN; break; } /* matrix coefficients */ switch (sequence->matrix_coefficients) { case 1: vinfo->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709; break; case 4: vinfo->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_FCC; break; case 5: case 6: vinfo->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601; break; case 7: vinfo->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M; break; /* 0 forbidden */ /* 2 unspecified */ /* 3 reserved */ /* 8-255 reseved */ default: vinfo->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN; break; } /* transfer characteristics */ switch (sequence->transfer_characteristics) { case 1: vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_BT709; break; case 4: vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA22; break; case 5: vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA28; break; case 6: vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_BT709; break; case 7: vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_SMPTE240M; break; case 8: vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA10; break; /* 0 forbidden */ /* 2 unspecified */ /* 3 reserved */ /* 9-255 reseved */ default: vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN; break; } } GST_DEBUG_OBJECT (mpeg2dec, "sequence flags: %d, frame period: %d, frame rate: %d/%d", sequence->flags, sequence->frame_period, vinfo->fps_n, vinfo->fps_d); GST_DEBUG_OBJECT (mpeg2dec, "profile: %02x, colour_primaries: %d", sequence->profile_level_id, sequence->colour_primaries); GST_DEBUG_OBJECT (mpeg2dec, "transfer chars: %d, matrix coef: %d", sequence->transfer_characteristics, sequence->matrix_coefficients); GST_DEBUG_OBJECT (mpeg2dec, "FLAGS: CONSTRAINED_PARAMETERS:%d, PROGRESSIVE_SEQUENCE:%d", sequence->flags & SEQ_FLAG_CONSTRAINED_PARAMETERS, sequence->flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE); GST_DEBUG_OBJECT (mpeg2dec, "FLAGS: LOW_DELAY:%d, COLOUR_DESCRIPTION:%d", sequence->flags & SEQ_FLAG_LOW_DELAY, sequence->flags & SEQ_FLAG_COLOUR_DESCRIPTION); /* we store the codec size before cropping */ *dinfo = *vinfo; gst_video_info_set_format (dinfo, format, sequence->width, sequence->height); /* Mpeg2dec has 2 frame latency to produce a picture and 1 frame latency in * it's parser */ latency = gst_util_uint64_scale (3, vinfo->fps_d, vinfo->fps_n); gst_video_decoder_set_latency (GST_VIDEO_DECODER (mpeg2dec), latency, latency); if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (mpeg2dec))) goto negotiation_fail; gst_video_codec_state_unref (state); mpeg2_custom_fbuf (mpeg2dec->decoder, 1); init_dummybuf (mpeg2dec); /* Pump in some null buffers, because otherwise libmpeg2 doesn't * initialise the discard_fbuf->id */ mpeg2_set_buf (mpeg2dec->decoder, mpeg2dec->dummybuf, NULL); mpeg2_set_buf (mpeg2dec->decoder, mpeg2dec->dummybuf, NULL); mpeg2_set_buf (mpeg2dec->decoder, mpeg2dec->dummybuf, NULL); gst_mpeg2dec_clear_buffers (mpeg2dec); return ret; invalid_frame_period: { GST_WARNING_OBJECT (mpeg2dec, "Frame period is 0!"); return GST_FLOW_ERROR; } invalid_size: { GST_ERROR_OBJECT (mpeg2dec, "Invalid frame dimensions: %d x %d", sequence->width, sequence->height); return GST_FLOW_ERROR; } negotiation_fail: { GST_WARNING_OBJECT (mpeg2dec, "Failed to negotiate with downstream"); return GST_FLOW_ERROR; } }
static void sample3 (FILE * mpgfile) { #define BUFFER_SIZE 4096 uint8_t buffer[BUFFER_SIZE]; mpeg2dec_t * decoder; const mpeg2_info_t * info; const mpeg2_sequence_t * sequence; mpeg2_state_t state; size_t size; int framenum = 0; uint8_t * fbuf[3][3]; int i, j; decoder = mpeg2_init (); if (decoder == NULL) { fprintf (stderr, "Could not allocate a decoder object.\n"); exit (1); } info = mpeg2_info (decoder); size = (size_t)-1; do { state = mpeg2_parse (decoder); sequence = info->sequence; switch (state) { case STATE_BUFFER: size = fread (buffer, 1, BUFFER_SIZE, mpgfile); mpeg2_buffer (decoder, buffer, buffer + size); break; case STATE_SEQUENCE: for (i = 0; i < 3; i++) { fbuf[i][0] = (uint8_t *) malloc (sequence->width * sequence->height); fbuf[i][1] = (uint8_t *) malloc (sequence->chroma_width * sequence->chroma_height); fbuf[i][2] = (uint8_t *) malloc (sequence->chroma_width * sequence->chroma_height); if (!fbuf[i][0] || !fbuf[i][1] || !fbuf[i][2]) { fprintf (stderr, "Could not allocate an output buffer.\n"); exit (1); } mpeg2_set_buf (decoder, fbuf[i], NULL); } break; case STATE_SLICE: case STATE_END: case STATE_INVALID_END: if (info->display_fbuf) save_pgm (sequence->width, sequence->height, sequence->chroma_width, sequence->chroma_height, info->display_fbuf->buf, framenum++); if (state != STATE_SLICE) for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) free (fbuf[i][j]); break; default: break; } } while (size); mpeg2_close (decoder); }
static int _initmpeg2(FILE *mpgfile,int *w, int *h) { static uint8_t buffer[BUFFER_SIZE]; mpeg2_state_t state; struct fbuf_s * current_fbuf; size_t size; int pixels; int i; global_mpegfile=mpgfile; if (decoder!=NULL) { mpeg2_close (decoder); decoder=NULL; } decoder = mpeg2_init (); if (decoder == NULL) { fprintf (stderr, "Could not allocate a decoder object.\n"); exit (1); } info = mpeg2_info (decoder); size = (size_t)-1; do { state = mpeg2_parse (decoder); if (state==STATE_BUFFER) { //fprintf(stderr,"Got STATE_BUFFER\n"); size = fread (buffer, 1, BUFFER_SIZE, global_mpegfile); mpeg2_buffer (decoder, buffer, buffer + size); } else if (state==STATE_SEQUENCE) { //fprintf(stderr,"Got STATE_SEQUENCE\n"); mpeg2_convert (decoder, mpeg2convert_rgb24, NULL); mpeg2_custom_fbuf (decoder, 1); if (w!=NULL) *w=info->sequence->width; if (h!=NULL) *h=info->sequence->height; pixels = info->sequence->width * info->sequence->height; for (i = 0; i < 3; i++) { fbuf[i].rgb[0] = (uint8_t *) malloc (3 * pixels); fbuf[i].rgb[1] = fbuf[i].rgb[2] = NULL; if (!fbuf[i].rgb[0]) { fprintf (stderr, "Could not allocate an output buffer.\n"); exit (1); } fbuf[i].used = 0; } for (i = 0; i < 2; i++) { current_fbuf = get_fbuf (); mpeg2_set_buf (decoder, current_fbuf->rgb, current_fbuf); } break; } else if (state==STATE_PICTURE || state==STATE_SLICE || state==STATE_END || state==STATE_INVALID_END) { //if (state==STATE_SLICE) fprintf(stderr,"Got STATE_PICTURE\n"); //if (state==STATE_SLICE) fprintf(stderr,"Got STATE_SLICE\n"); //if (state==STATE_END) fprintf(stderr,"Got STATE_END\n"); //if (state==STATE_INVALID_END) fprintf(stderr,"Got STATE_INVALID_END\n"); fprintf(stderr,"GOT unexpected state during initialization.\n"); return 0; } } while (size); return 1; }
int _getmpeg2frame(unsigned char *rgb,int gray) { int i; static uint8_t buffer[BUFFER_SIZE]; mpeg2_state_t state; size_t size; int pixels; struct fbuf_s * current_fbuf; int done=0; size = (size_t)-1; do { state = mpeg2_parse (decoder); if (state==STATE_BUFFER) { //fprintf(stderr,"Got STATE_BUFFER\n"); size = fread (buffer, 1, BUFFER_SIZE, global_mpegfile); mpeg2_buffer (decoder, buffer, buffer + size); } else if (state==STATE_SEQUENCE) { //fprintf(stderr,"Got STATE_SEQUENCE\n"); mpeg2_convert (decoder, mpeg2convert_rgb24, NULL); mpeg2_custom_fbuf (decoder, 1); pixels = info->sequence->width * info->sequence->height; for (i = 0; i < 3; i++) { fbuf[i].rgb[0] = (uint8_t *) malloc (3 * pixels); fbuf[i].rgb[1] = fbuf[i].rgb[2] = NULL; if (!fbuf[i].rgb[0]) { fprintf (stderr, "Could not allocate an output buffer.\n"); exit (1); } fbuf[i].used = 0; } for (i = 0; i < 2; i++) { current_fbuf = get_fbuf (); mpeg2_set_buf (decoder, current_fbuf->rgb, current_fbuf); } } else if (state==STATE_PICTURE) { //fprintf(stderr,"Got STATE_PICTURE\n"); current_fbuf = get_fbuf (); mpeg2_set_buf (decoder, current_fbuf->rgb, current_fbuf); } else if (state==STATE_SLICE || state==STATE_END || state==STATE_INVALID_END) { //if (state==STATE_SLICE) fprintf(stderr,"Got STATE_SLICE\n"); //if (state==STATE_END) fprintf(stderr,"Got STATE_END\n"); //if (state==STATE_INVALID_END) fprintf(stderr,"Got STATE_INVALID_END\n"); if (info->display_fbuf) { int jj; int pixels; uint8_t *base; base=info->display_fbuf->buf[0]; /* we have a complete image ready */ if (gray) { pixels=info->sequence->width*info->sequence->height; for (jj=0;jj<pixels;jj++) { rgb[jj]=(base[0]+base[1]+base[3])/3; base+=3; } } else { pixels=3*info->sequence->width*info->sequence->height; /* we have a complete image ready */ memcpy(rgb,base,pixels*sizeof(unsigned char)); } done=1; } if (info->discard_fbuf) ((struct fbuf_s *)info->discard_fbuf->id)->used = 0; if (state != STATE_SLICE) for (i = 0; i < 3; i++) free (fbuf[i].rgb[0]); if (state==STATE_END) { //fprintf(stderr,"Got STATE_END\n"); rewindmpeg2(); } if (state==STATE_INVALID_END) { //fprintf(stderr,"Got STATE_INVALID_END\n"); rewindmpeg2(); } /* we got a single frame */ if (done) { if (size!=0) return 1; return 0; } } } while (size); return 0; }
int PrivateDecoderMPEG2::GetFrame(AVStream *stream, AVFrame *picture, int *got_picture_ptr, AVPacket *pkt) { AVCodecContext *avctx = stream->codec; *got_picture_ptr = 0; const mpeg2_info_t *info = mpeg2_info(mpeg2dec); mpeg2_buffer(mpeg2dec, pkt->data, pkt->data + pkt->size); while (1) { switch (mpeg2_parse(mpeg2dec)) { case STATE_SEQUENCE: // libmpeg2 needs three buffers to do its work. // We set up two prediction buffers here, from // the set of available video frames. mpeg2_custom_fbuf(mpeg2dec, 1); for (int i = 0; i < 2; i++) { avctx->get_buffer(avctx, picture); mpeg2_set_buf(mpeg2dec, picture->data, picture->opaque); } break; case STATE_PICTURE: // This sets up the third buffer for libmpeg2. // We use up one of the three buffers for each // frame shown. The frames get released once // they are drawn (outside this routine). avctx->get_buffer(avctx, picture); mpeg2_set_buf(mpeg2dec, picture->data, picture->opaque); break; case STATE_BUFFER: // We're finished with the buffer... if (partialFrames.size()) { AVFrame *frm = partialFrames.dequeue(); *got_picture_ptr = 1; *picture = *frm; delete frm; #if 0 QString msg(""); AvFormatDecoder *nd = (AvFormatDecoder *)(avctx->opaque); if (nd && nd->GetNVP() && nd->GetNVP()->getVideoOutput()) msg = nd->GetNVP()->getVideoOutput()->GetFrameStatus(); VERBOSE(VB_IMPORTANT, "ret frame: "<<picture->opaque <<" "<<msg); #endif } return pkt->size; case STATE_INVALID: // This is the error state. The decoder must be // reset on an error. Reset(); return -1; case STATE_SLICE: case STATE_END: case STATE_INVALID_END: if (info->display_fbuf) { bool exists = false; avframe_q::iterator it = partialFrames.begin(); for (; it != partialFrames.end(); ++it) if ((*it)->opaque == info->display_fbuf->id) exists = true; if (!exists) { AVFrame *frm = new AVFrame(); frm->data[0] = info->display_fbuf->buf[0]; frm->data[1] = info->display_fbuf->buf[1]; frm->data[2] = info->display_fbuf->buf[2]; frm->data[3] = NULL; frm->opaque = info->display_fbuf->id; frm->type = FF_BUFFER_TYPE_USER; frm->top_field_first = !!(info->display_picture->flags & PIC_FLAG_TOP_FIELD_FIRST); frm->interlaced_frame = !(info->display_picture->flags & PIC_FLAG_PROGRESSIVE_FRAME); frm->repeat_pict = !!(info->display_picture->flags & #if CONFIG_LIBMPEG2EXTERNAL PIC_FLAG_REPEAT_FIRST_FIELD); #else PIC_FLAG_REPEAT_FIELD); #endif partialFrames.enqueue(frm); } } if (info->discard_fbuf) { bool exists = false; avframe_q::iterator it = partialFrames.begin(); for (; it != partialFrames.end(); ++it) { if ((*it)->opaque == info->discard_fbuf->id) { exists = true; (*it)->data[3] = (unsigned char*) 1; } } if (!exists) { AVFrame frame; frame.opaque = info->discard_fbuf->id; frame.type = FF_BUFFER_TYPE_USER; avctx->release_buffer(avctx, &frame); } } break; default: break; }
static GstFlowReturn handle_picture (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info, GstVideoCodecFrame * frame) { GstVideoDecoder *decoder = (GstVideoDecoder *) mpeg2dec; GstFlowReturn ret; gint type; const gchar *type_str = NULL; gboolean key_frame = FALSE; const mpeg2_picture_t *picture = info->current_picture; GstVideoFrame vframe; guint8 *buf[3]; ret = gst_video_decoder_allocate_output_frame (decoder, frame); if (ret != GST_FLOW_OK) return ret; type = picture->flags & PIC_MASK_CODING_TYPE; switch (type) { case PIC_FLAG_CODING_TYPE_I: key_frame = TRUE; mpeg2_skip (mpeg2dec->decoder, 0); type_str = "I"; break; case PIC_FLAG_CODING_TYPE_P: type_str = "P"; break; case PIC_FLAG_CODING_TYPE_B: type_str = "B"; break; default: gst_video_codec_frame_ref (frame); ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (mpeg2dec), frame); GST_VIDEO_DECODER_ERROR (mpeg2dec, 1, STREAM, DECODE, ("decoding error"), ("Invalid picture type"), ret); return ret; } GST_DEBUG_OBJECT (mpeg2dec, "handle picture type %s", type_str); GST_DEBUG_OBJECT (mpeg2dec, "picture %s, frame %i", key_frame ? ", kf," : " ", frame->system_frame_number); if (GST_VIDEO_INFO_IS_INTERLACED (&mpeg2dec->decoded_info)) { /* This implies SEQ_FLAG_PROGRESSIVE_SEQUENCE is not set */ if (picture->flags & PIC_FLAG_TOP_FIELD_FIRST) { GST_BUFFER_FLAG_SET (frame->output_buffer, GST_VIDEO_BUFFER_FLAG_TFF); } if (!(picture->flags & PIC_FLAG_PROGRESSIVE_FRAME)) { GST_BUFFER_FLAG_SET (frame->output_buffer, GST_VIDEO_BUFFER_FLAG_INTERLACED); } #if MPEG2_RELEASE >= MPEG2_VERSION(0,5,0) /* repeat field introduced in 0.5.0 */ if (picture->flags & PIC_FLAG_REPEAT_FIRST_FIELD) { GST_BUFFER_FLAG_SET (frame->output_buffer, GST_VIDEO_BUFFER_FLAG_RFF); } #endif } if (mpeg2dec->discont_state == MPEG2DEC_DISC_NEW_PICTURE && key_frame) { mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_KEYFRAME; } GST_DEBUG_OBJECT (mpeg2dec, "picture: %s %s %s %s %s fields:%d ts:%" GST_TIME_FORMAT, (picture->flags & PIC_FLAG_PROGRESSIVE_FRAME ? "prog" : " "), (picture->flags & PIC_FLAG_TOP_FIELD_FIRST ? "tff" : " "), #if MPEG2_RELEASE >= MPEG2_VERSION(0,5,0) (picture->flags & PIC_FLAG_REPEAT_FIRST_FIELD ? "rff" : " "), #else "unknown rff", #endif (picture->flags & PIC_FLAG_SKIP ? "skip" : " "), (picture->flags & PIC_FLAG_COMPOSITE_DISPLAY ? "composite" : " "), picture->nb_fields, GST_TIME_ARGS (frame->pts)); if (!gst_video_frame_map (&vframe, &mpeg2dec->decoded_info, frame->output_buffer, GST_MAP_READ | GST_MAP_WRITE)) goto map_fail; buf[0] = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0); buf[1] = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 1); buf[2] = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 2); GST_DEBUG_OBJECT (mpeg2dec, "set_buf: %p %p %p, frame %i", buf[0], buf[1], buf[2], frame->system_frame_number); /* Note: We use a non-null 'id' value to make the distinction * between the dummy buffers (which have an id of NULL) and the * ones we did */ mpeg2_stride (mpeg2dec->decoder, vframe.info.stride[0]); mpeg2_set_buf (mpeg2dec->decoder, buf, GINT_TO_POINTER (frame->system_frame_number + 1)); gst_mpeg2dec_save_buffer (mpeg2dec, frame->system_frame_number, &vframe); return ret; map_fail: { GST_ELEMENT_ERROR (mpeg2dec, RESOURCE, WRITE, ("Failed to map frame"), (NULL)); return GST_FLOW_ERROR; } }