static gboolean gst_mpeg2dec_flush (GstVideoDecoder * decoder) { GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (decoder); /* reset the initial video state */ mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE; mpeg2_reset (mpeg2dec->decoder, 1); mpeg2_skip (mpeg2dec->decoder, 1); gst_mpeg2dec_clear_buffers (mpeg2dec); return TRUE; }
static gboolean gst_mpeg2dec_close (GstVideoDecoder * decoder) { GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (decoder); if (mpeg2dec->decoder) { mpeg2_close (mpeg2dec->decoder); mpeg2dec->decoder = NULL; mpeg2dec->info = NULL; } gst_mpeg2dec_clear_buffers (mpeg2dec); return TRUE; }
static gboolean gst_mpeg2dec_stop (GstVideoDecoder * decoder) { GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (decoder); mpeg2_reset (mpeg2dec->decoder, 0); mpeg2_skip (mpeg2dec->decoder, 1); gst_mpeg2dec_clear_buffers (mpeg2dec); if (mpeg2dec->input_state) gst_video_codec_state_unref (mpeg2dec->input_state); mpeg2dec->input_state = NULL; return TRUE; }
static void gst_mpeg2dec_finalize (GObject * object) { GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (object); if (mpeg2dec->decoder) { GST_DEBUG_OBJECT (mpeg2dec, "closing decoder"); mpeg2_close (mpeg2dec->decoder); mpeg2dec->decoder = NULL; } gst_mpeg2dec_clear_buffers (mpeg2dec); g_free (mpeg2dec->dummybuf[3]); mpeg2dec->dummybuf[3] = NULL; G_OBJECT_CLASS (parent_class)->finalize (object); }
static gboolean gst_mpeg2dec_stop (GstVideoDecoder * decoder) { GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (decoder); mpeg2_reset (mpeg2dec->decoder, 0); mpeg2_skip (mpeg2dec->decoder, 1); gst_mpeg2dec_clear_buffers (mpeg2dec); if (mpeg2dec->input_state) gst_video_codec_state_unref (mpeg2dec->input_state); mpeg2dec->input_state = NULL; if (mpeg2dec->downstream_pool) { gst_buffer_pool_set_active (mpeg2dec->downstream_pool, FALSE); gst_object_unref (mpeg2dec->downstream_pool); } return TRUE; }
static GstFlowReturn gst_mpeg2dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame) { GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (decoder); GstBuffer *buf = frame->input_buffer; GstMapInfo minfo; const mpeg2_info_t *info; mpeg2_state_t state; gboolean done = FALSE; GstFlowReturn ret = GST_FLOW_OK; GST_LOG_OBJECT (mpeg2dec, "received frame %d, timestamp %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, frame->system_frame_number, GST_TIME_ARGS (frame->pts), GST_TIME_ARGS (frame->duration)); gst_buffer_ref (buf); if (!gst_buffer_map (buf, &minfo, GST_MAP_READ)) { GST_ERROR_OBJECT (mpeg2dec, "Failed to map input buffer"); return GST_FLOW_ERROR; } info = mpeg2dec->info; GST_LOG_OBJECT (mpeg2dec, "calling mpeg2_buffer"); mpeg2_buffer (mpeg2dec->decoder, minfo.data, minfo.data + minfo.size); GST_LOG_OBJECT (mpeg2dec, "calling mpeg2_buffer done"); while (!done) { GST_LOG_OBJECT (mpeg2dec, "calling parse"); state = mpeg2_parse (mpeg2dec->decoder); GST_DEBUG_OBJECT (mpeg2dec, "parse state %d", state); switch (state) { #if MPEG2_RELEASE >= MPEG2_VERSION (0, 5, 0) case STATE_SEQUENCE_MODIFIED: GST_DEBUG_OBJECT (mpeg2dec, "sequence modified"); mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE; gst_mpeg2dec_clear_buffers (mpeg2dec); /* fall through */ #endif case STATE_SEQUENCE: ret = handle_sequence (mpeg2dec, info); /* if there is an error handling the sequence * reset the decoder, maybe something more elegant * could be done. */ if (ret == GST_FLOW_ERROR) { GST_VIDEO_DECODER_ERROR (decoder, 1, STREAM, DECODE, ("decoding error"), ("Bad sequence header"), ret); gst_video_decoder_drop_frame (decoder, frame); gst_mpeg2dec_flush (decoder); goto done; } break; case STATE_SEQUENCE_REPEATED: GST_DEBUG_OBJECT (mpeg2dec, "sequence repeated"); break; case STATE_GOP: GST_DEBUG_OBJECT (mpeg2dec, "gop"); break; case STATE_PICTURE: ret = handle_picture (mpeg2dec, info, frame); break; case STATE_SLICE_1ST: GST_LOG_OBJECT (mpeg2dec, "1st slice of frame encountered"); break; case STATE_PICTURE_2ND: GST_LOG_OBJECT (mpeg2dec, "Second picture header encountered. Decoding 2nd field"); break; #if MPEG2_RELEASE >= MPEG2_VERSION (0, 4, 0) case STATE_INVALID_END: GST_DEBUG_OBJECT (mpeg2dec, "invalid end"); #endif case STATE_END: GST_DEBUG_OBJECT (mpeg2dec, "end"); case STATE_SLICE: GST_DEBUG_OBJECT (mpeg2dec, "display_fbuf:%p, discard_fbuf:%p", info->display_fbuf, info->discard_fbuf); if (info->display_fbuf && info->display_fbuf->id) { ret = handle_slice (mpeg2dec, info); } else { GST_DEBUG_OBJECT (mpeg2dec, "no picture to display"); } if (info->discard_fbuf && info->discard_fbuf->id) gst_mpeg2dec_discard_buffer (mpeg2dec, GPOINTER_TO_INT (info->discard_fbuf->id) - 1); if (state != STATE_SLICE) { gst_mpeg2dec_clear_buffers (mpeg2dec); } break; case STATE_BUFFER: done = TRUE; break; /* error */ case STATE_INVALID: GST_VIDEO_DECODER_ERROR (decoder, 1, STREAM, DECODE, ("decoding error"), ("Reached libmpeg2 invalid state"), ret); continue; default: GST_ERROR_OBJECT (mpeg2dec, "Unknown libmpeg2 state %d, FIXME", state); ret = GST_FLOW_OK; gst_video_codec_frame_unref (frame); goto done; } if (ret != GST_FLOW_OK) { GST_DEBUG_OBJECT (mpeg2dec, "exit loop, reason %s", gst_flow_get_name (ret)); break; } } gst_video_codec_frame_unref (frame); done: gst_buffer_unmap (buf, &minfo); gst_buffer_unref (buf); return ret; }
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; } }