diff --git a/ext/opus/gstopusenc.c b/ext/opus/gstopusenc.c index 999c0f39f1..fd2f0ad625 100644 --- a/ext/opus/gstopusenc.c +++ b/ext/opus/gstopusenc.c @@ -345,6 +345,7 @@ gst_opus_enc_stop (GstAudioEncoder * benc) gst_tag_list_free (enc->tags); enc->tags = NULL; g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL); + g_slist_free (enc->headers); enc->headers = NULL; gst_tag_setter_reset_tags (GST_TAG_SETTER (enc)); @@ -879,6 +880,7 @@ gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf) GstCaps *caps; g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL); + g_slist_free (enc->headers); enc->headers = NULL; gst_opus_header_create_caps (&caps, &enc->headers, enc->n_channels, @@ -891,6 +893,7 @@ gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf) GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps); gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps); + gst_caps_unref (caps); enc->header_sent = TRUE; } diff --git a/ext/vp8/GstVP8Enc.prs b/ext/vp8/GstVP8Enc.prs new file mode 100644 index 0000000000..6e1d13d9b2 --- /dev/null +++ b/ext/vp8/GstVP8Enc.prs @@ -0,0 +1,7 @@ +[_presets_] +version=0.10 +element-name=GstVP8Enc + +[Profile Realtime] +max-latency=1 +speed=2 diff --git a/ext/vp8/Makefile.am b/ext/vp8/Makefile.am index d839666fda..312966c6a5 100644 --- a/ext/vp8/Makefile.am +++ b/ext/vp8/Makefile.am @@ -24,3 +24,8 @@ noinst_HEADERS = \ gstvp8dec.h \ gstvp8enc.h \ gstvp8utils.h + +presetdir = $(datadir)/gstreamer-$(GST_MAJORMINOR)/presets +preset_DATA = GstVP8Enc.prs + +EXTRA_DIST = $(preset_DATA) diff --git a/ext/vp8/gstvp8dec.c b/ext/vp8/gstvp8dec.c index 1172ac96e2..c4d17a7b7d 100644 --- a/ext/vp8/gstvp8dec.c +++ b/ext/vp8/gstvp8dec.c @@ -493,6 +493,7 @@ gst_vp8_dec_handle_frame (GstBaseVideoDecoder * decoder, } } else { /* Invisible frame */ + frame->decode_only = 1; gst_base_video_decoder_finish_frame (decoder, frame); } diff --git a/gst-libs/gst/codecparsers/gstmpeg4parser.c b/gst-libs/gst/codecparsers/gstmpeg4parser.c index 302219fc13..4b0acb6b59 100644 --- a/gst-libs/gst/codecparsers/gstmpeg4parser.c +++ b/gst-libs/gst/codecparsers/gstmpeg4parser.c @@ -273,7 +273,7 @@ find_psc (GstByteReader * br) /* Scan for the picture start code (22 bits - 0x0020) */ while ((gst_byte_reader_get_remaining (br) >= 3)) { if (gst_byte_reader_peek_uint24_be (br, &psc) && - ((psc & 0xffffc0) == 0x000080)) { + ((psc & 0xfffffc) == 0x000080)) { psc_pos = gst_byte_reader_get_pos (br); break; } else @@ -473,8 +473,7 @@ gst_mpeg4_parse (GstMpeg4Packet * packet, gboolean skip_user_data, if (skip_user_data && data[off1 + 3] == GST_MPEG4_USER_DATA) /* If we are here, we know no resync code has been found the first time, so we * don't look for it this time */ - return gst_mpeg4_parse (packet, skip_user_data, NULL, data, off1 + 3, - size - off1 - 3); + return gst_mpeg4_parse (packet, skip_user_data, NULL, data, off1 + 3, size); packet->offset = off1 + 3; packet->data = data; @@ -524,7 +523,7 @@ gst_h263_parse (GstMpeg4Packet * packet, gint off1, off2; GstByteReader br; - gst_byte_reader_init (&br, data, size); + gst_byte_reader_init (&br, data + offset, size - offset); g_return_val_if_fail (packet != NULL, GST_MPEG4_PARSER_ERROR); @@ -541,9 +540,10 @@ gst_h263_parse (GstMpeg4Packet * packet, return GST_MPEG4_PARSER_NO_PACKET; } - packet->offset = off1; + packet->offset = off1 + offset; packet->data = data; + gst_byte_reader_skip (&br, 3); off2 = find_psc (&br); if (off2 == -1) { @@ -1490,18 +1490,24 @@ gst_mpeg4_parse_video_plane_short_header (GstMpeg4VideoPlaneShortHdr * shorthdr, const guint8 * data, gsize size) { guint8 zero_bits; - guint32 gob_resync; GstBitReader br = GST_BIT_READER_INIT (data, size); g_return_val_if_fail (shorthdr != NULL, GST_MPEG4_PARSER_ERROR); - if (gst_bit_reader_get_remaining (&br) < 26) + if (gst_bit_reader_get_remaining (&br) < 48) + goto failed; + + if (gst_bit_reader_get_bits_uint32_unchecked (&br, 22) != 0x20) goto failed; shorthdr->temporal_reference = gst_bit_reader_get_bits_uint8_unchecked (&br, 8); CHECK_MARKER (&br); + zero_bits = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + if (zero_bits != 0x00) + goto failed; + shorthdr->split_screen_indicator = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); shorthdr->document_camera_indicator = @@ -1517,26 +1523,31 @@ gst_mpeg4_parse_video_plane_short_header (GstMpeg4VideoPlaneShortHdr * shorthdr->vop_height = 96; shorthdr->num_macroblocks_in_gob = 8; shorthdr->num_gobs_in_vop = 6; + break; case 0x02: shorthdr->vop_width = 176; shorthdr->vop_height = 144; shorthdr->num_macroblocks_in_gob = 11; shorthdr->num_gobs_in_vop = 9; + break; case 0x03: shorthdr->vop_width = 352; shorthdr->vop_height = 288; shorthdr->num_macroblocks_in_gob = 22; shorthdr->num_gobs_in_vop = 18; + break; case 0x04: shorthdr->vop_width = 704; shorthdr->vop_height = 576; shorthdr->num_macroblocks_in_gob = 88; shorthdr->num_gobs_in_vop = 18; + break; case 0x05: shorthdr->vop_width = 1408; shorthdr->vop_height = 1152; shorthdr->num_macroblocks_in_gob = 352; shorthdr->num_gobs_in_vop = 18; + break; default: shorthdr->vop_width = 0; shorthdr->vop_height = 0; @@ -1565,26 +1576,6 @@ gst_mpeg4_parse_video_plane_short_header (GstMpeg4VideoPlaneShortHdr * } while (shorthdr->pei == 1); - if (!gst_bit_reader_peek_bits_uint32 (&br, &gob_resync, 17)) - goto failed; - - /* gob_layer() */ - - /* Setting default values */ - shorthdr->gob_header_empty = 1; - shorthdr->gob_number = 0; - shorthdr->gob_frame_id = 0; - shorthdr->quant_scale = 0; - - if (gob_resync == 0x01) { - shorthdr->gob_header_empty = 0; - - gst_bit_reader_skip_unchecked (&br, 17); - READ_UINT8 (&br, shorthdr->gob_number, 5); - READ_UINT8 (&br, shorthdr->gob_frame_id, 2); - READ_UINT8 (&br, shorthdr->quant_scale, 5); - } - shorthdr->size = gst_bit_reader_get_pos (&br); return GST_MPEG4_PARSER_OK; diff --git a/gst-libs/gst/video/gstbasevideocodec.h b/gst-libs/gst/video/gstbasevideocodec.h index fb4ee7fec9..dafd995da9 100644 --- a/gst-libs/gst/video/gstbasevideocodec.h +++ b/gst-libs/gst/video/gstbasevideocodec.h @@ -126,6 +126,10 @@ struct _GstVideoFrameState gboolean is_sync_point; gboolean is_eos; + /* Frames that should not be pushed downstream and are + * not meant for display */ + gboolean decode_only; + GstBuffer *sink_buffer; GstBuffer *src_buffer; diff --git a/gst-libs/gst/video/gstbasevideodecoder.c b/gst-libs/gst/video/gstbasevideodecoder.c index 5a7519cb68..8b0ad8eedf 100644 --- a/gst-libs/gst/video/gstbasevideodecoder.c +++ b/gst-libs/gst/video/gstbasevideodecoder.c @@ -1397,6 +1397,11 @@ gst_base_video_decoder_prepare_finish_frame (GstBaseVideoDecoder * } g_list_free (events); + /* Check if the data should not be displayed. For example altref/invisible + * frame in vp8. In this case we should not update the timestamps. */ + if (frame->decode_only) + return; + if (GST_CLOCK_TIME_IS_VALID (frame->presentation_timestamp)) { if (frame->presentation_timestamp != base_video_decoder->timestamp_offset) { GST_DEBUG_OBJECT (base_video_decoder, @@ -1552,7 +1557,7 @@ gst_base_video_decoder_finish_frame (GstBaseVideoDecoder * base_video_decoder, base_video_decoder->processed++; /* no buffer data means this frame is skipped */ - if (!frame->src_buffer) { + if (!frame->src_buffer || frame->decode_only) { GST_DEBUG_OBJECT (base_video_decoder, "skipping frame %" GST_TIME_FORMAT, GST_TIME_ARGS (frame->presentation_timestamp)); goto done; diff --git a/gst/coloreffects/gstcoloreffects.c b/gst/coloreffects/gstcoloreffects.c index df78b86601..34ade3215f 100644 --- a/gst/coloreffects/gstcoloreffects.c +++ b/gst/coloreffects/gstcoloreffects.c @@ -86,6 +86,8 @@ gst_color_effects_preset_get_type (void) {GST_COLOR_EFFECTS_PRESET_XRAY, "Invert and slightly shade to blue", "xray"}, {GST_COLOR_EFFECTS_PRESET_XPRO, "Cross processing toning", "xpro"}, + {GST_COLOR_EFFECTS_PRESET_YELLOWBLUE, + "Yellow foreground Blue background color filter", "yellowblue"}, {0, NULL, NULL}, }; @@ -253,6 +255,38 @@ static const guint8 xpro_table[768] = "\376\365\377\377\365\377\377\366\377\377\366\377\377\366\377\377\367\377" "\377\367\377\377\367\377\377\370"; +/*Used for a video magnifer emulator in gnome-video-effects*/ +static const guint8 yellowblue_table[768] = + "\0\0\377\1\1\376\2\2\375\3\3\374\4\4\373\5\5\372\6\6\371\7\7\370\10\10\367" + "\11\11\367\12\12\365\13\13\364\14\14\363\15\14\362\16\16\361\17\17\360\20" + "\20\357\20\21\356\22\22\355\23\23\354\24\24\354\24\25\352\26\26\351\27\27" + "\350\27\30\347\31\31\346\32\32\345\33\32\344\34\34\343\34\34\342\36\36\341" + "\37\36\340\40\40\337!!\336!!\335##\334$#\334%%\332&%\331'&\330((\327()\326" + "*)\325++\324,,\323--\322..\321//\320/0\31711\31722\31522\31444\31445\313" + "55\31276\31188\30799\3069:\305;;\305<<\304==\302>>\301>>\300@@\300@A\276" + "AB\275BC\274CD\273DE\272EE\272FF\270HH\270HI\266IJ\265KK\264KL\263MM\262" + "NN\262NN\261OO\257QP\256RQ\256RR\254TT\253UU\253VU\251VW\250XX\247XY\246" + "YZ\245[[\245[[\243]]\243^^\242^_\240_`\237`a\236aa\235bb\235dc\233de\233" + "ff\232gf\231hg\230hi\227ji\226kj\225lk\223lm\223nm\222nn\221op\217qq\216" + "rr\215ss\214st\213uu\213uu\211wv\210ww\207xx\207yz\205z{\205{{\204||\203" + "}}\202\177~\201\177\200\177\200\201\177\202\202~\203\202|\204\203|\204\204" + "{\205\206z\207\206x\207\207w\211\210w\211\211v\212\212u\213\214s\214\214" + "r\215\215r\216\217q\217\217p\221\220o\221\222n\223\222l\224\223k\224\224" + "k\225\225j\226\226i\227\227h\230\231f\231\231f\233\232e\233\233c\234\234" + "c\235\235b\236\236a\237\237`\241\240_\242\241^\242\242]\243\244\\\244\244" + "[\245\245Y\246\246Y\250\247X\250\250W\251\251V\252\252T\253\253T\254\255" + "S\256\255R\257\256Q\257\260P\260\261O\261\261N\262\262M\263\263L\264\265" + "K\265\265J\266\266I\267\270H\270\270G\271\271F\272\272E\273\273C\274\274" + "B\275\275B\276\276A\277\277@\300\300?\301\301>\302\302=\303\303<\304\304" + ";\305\305:\306\3069\307\3078\310\3107\311\3116\312\3125\313\3134\314\314" + "3\315\3152\316\3161\317\3170\320\320/\321\321.\322\322-\323\323,\323\324" + "+\325\325*\326\326)\327\327(\330\330'\331\331&\332\331%\333\332$\334\334" + "#\334\335\"\336\336!\337\337\40\340\340\37\341\341\36\342\342\35\343\343" + "\34\344\344\33\345\345\32\345\346\31\347\347\30\350\350\27\351\351\26\352" + "\352\25\353\353\24\354\354\23\354\355\22\356\356\21\357\357\20\360\360\17" + "\361\361\16\362\362\15\363\362\14\364\364\13\365\365\12\365\366\11\367\367" + "\11\370\370\7\371\371\6\372\371\5\373\373\4\374\374\4\375\375\3\375\376\1"; + static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = { 298, 0, 409, -57068, 298, -100, -208, 34707, @@ -543,6 +577,10 @@ gst_color_effects_set_property (GObject * object, guint prop_id, filter->table = xpro_table; filter->map_luma = FALSE; break; + case GST_COLOR_EFFECTS_PRESET_YELLOWBLUE: + filter->table = yellowblue_table; + filter->map_luma = FALSE; + break; default: g_assert_not_reached (); diff --git a/gst/coloreffects/gstcoloreffects.h b/gst/coloreffects/gstcoloreffects.h index 04e52a9038..e2ae65f946 100644 --- a/gst/coloreffects/gstcoloreffects.h +++ b/gst/coloreffects/gstcoloreffects.h @@ -45,6 +45,7 @@ typedef struct _GstColorEffectsClass GstColorEffectsClass; * @GST_CLUT_PRESET_SEPIA: Sepia toning filter * @GST_CLUT_PRESET_XRAY: Invert colors and slightly shade to cyan * @GST_CLUT_PRESET_XPRO: Cross Processing filter + * @GST_CLUT_PRESET_YELLOWBLUE: Visual magnifier high-contrast color filter. Since: 0.10.24 * * The lookup table to use to convert input colors */ @@ -54,7 +55,8 @@ typedef enum GST_COLOR_EFFECTS_PRESET_HEAT, GST_COLOR_EFFECTS_PRESET_SEPIA, GST_COLOR_EFFECTS_PRESET_XRAY, - GST_COLOR_EFFECTS_PRESET_XPRO + GST_COLOR_EFFECTS_PRESET_XPRO, + GST_COLOR_EFFECTS_PRESET_YELLOWBLUE, } GstColorEffectsPreset; /** diff --git a/gst/interlace/gstinterlace.c b/gst/interlace/gstinterlace.c index c6181ecad5..bc319b9bf5 100644 --- a/gst/interlace/gstinterlace.c +++ b/gst/interlace/gstinterlace.c @@ -187,6 +187,7 @@ static gboolean gst_interlace_setcaps (GstPad * pad, GstCaps * caps); static GstCaps *gst_interlace_getcaps (GstPad * pad); static GstStateChangeReturn gst_interlace_change_state (GstElement * element, GstStateChange transition); +static void gst_interlace_finalize (GObject * obj); static GstElementClass *parent_class = NULL; @@ -242,6 +243,7 @@ gst_interlace_class_init (GstInterlaceClass * klass) object_class->set_property = gst_interlace_set_property; object_class->get_property = gst_interlace_get_property; + object_class->finalize = gst_interlace_finalize; element_class->change_state = gst_interlace_change_state; @@ -268,6 +270,16 @@ gst_interlace_class_init (GstInterlaceClass * klass) } +static void +gst_interlace_finalize (GObject * obj) +{ + GstInterlace *interlace = GST_INTERLACE (obj); + + gst_caps_replace (&interlace->srccaps, NULL); + + G_OBJECT_CLASS (parent_class)->finalize (obj); +} + static void gst_interlace_reset (GstInterlace * interlace) { @@ -328,13 +340,19 @@ gst_interlace_decorate_buffer (GstInterlace * interlace, GstBuffer * buf, int n_fields) { /* field duration = src_fps_d / (2 * src_fps_n) */ - GST_BUFFER_TIMESTAMP (buf) = interlace->timebase + - gst_util_uint64_scale (GST_SECOND, - interlace->src_fps_d * interlace->fields_since_timebase, - interlace->src_fps_n * 2); - GST_BUFFER_DURATION (buf) = - gst_util_uint64_scale (GST_SECOND, interlace->src_fps_d * n_fields, - interlace->src_fps_n * 2); + if (interlace->src_fps_n == 0) { + /* If we don't know the fps, we can't generate timestamps/durations */ + GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE; + GST_BUFFER_DURATION (buf) = GST_CLOCK_TIME_NONE; + } else { + GST_BUFFER_TIMESTAMP (buf) = interlace->timebase + + gst_util_uint64_scale (GST_SECOND, + interlace->src_fps_d * interlace->fields_since_timebase, + interlace->src_fps_n * 2); + GST_BUFFER_DURATION (buf) = + gst_util_uint64_scale (GST_SECOND, interlace->src_fps_d * n_fields, + interlace->src_fps_n * 2); + } /* increment the buffer timestamp by duration for the next buffer */ gst_buffer_set_caps (buf, interlace->srccaps); @@ -457,6 +475,8 @@ gst_interlace_getcaps (GstPad * pad) gst_caps_set_simple (icaps, "interlaced", G_TYPE_BOOLEAN, pad == interlace->srcpad ? TRUE : FALSE, NULL); + gst_object_unref (interlace); + return icaps; } @@ -470,7 +490,7 @@ gst_interlace_setcaps (GstPad * pad, GstCaps * caps) gboolean interlaced = TRUE; int fps_n, fps_d; GstPad *otherpad; - GstCaps *othercaps; + GstCaps *othercaps = NULL; const PulldownFormat *pdformat; interlace = GST_INTERLACE (gst_pad_get_parent (pad)); @@ -519,6 +539,8 @@ gst_interlace_setcaps (GstPad * pad, GstCaps * caps) } error: + if (othercaps) + gst_caps_unref (othercaps); g_object_unref (interlace); return ret; diff --git a/gst/mpegtsdemux/tsdemux.c b/gst/mpegtsdemux/tsdemux.c index 4e66122c89..4f51abd5c3 100644 --- a/gst/mpegtsdemux/tsdemux.c +++ b/gst/mpegtsdemux/tsdemux.c @@ -63,6 +63,7 @@ #define PCR_SMALL 17775000 /* maximal PCR time */ #define PCR_MAX_VALUE (((((guint64)1)<<33) * 300) + 298) +#define PTS_DTS_MAX_VALUE (((guint64)1) << 33) /* seek to SEEK_TIMESTAMP_OFFSET before the desired offset and search then * either accurately or for the next timestamp @@ -72,6 +73,8 @@ GST_DEBUG_CATEGORY_STATIC (ts_demux_debug); #define GST_CAT_DEFAULT ts_demux_debug +#define ABSDIFF(a,b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) + static GQuark QUARK_TSDEMUX; static GQuark QUARK_PID; static GQuark QUARK_PCR; @@ -114,8 +117,15 @@ struct _TSDemuxStream /* Current data to be pushed out */ GList *currentlist; - /* Current PTS for this stream */ + /* Current PTS/DTS for this stream */ GstClockTime pts; + GstClockTime dts; + /* Raw value of current PTS/DTS */ + guint64 raw_pts; + guint64 raw_dts; + /* Number of rollover seen for PTS/DTS (default:0) */ + guint nb_pts_rollover; + guint nb_dts_rollover; }; #define VIDEO_CAPS \ @@ -1238,7 +1248,13 @@ gst_ts_demux_stream_added (MpegTSBase * base, MpegTSBaseStream * bstream, /* Create the pad */ if (bstream->stream_type != 0xff) stream->pad = create_pad_for_stream (base, bstream, program); + stream->pts = GST_CLOCK_TIME_NONE; + stream->dts = GST_CLOCK_TIME_NONE; + stream->raw_pts = 0; + stream->raw_dts = 0; + stream->nb_pts_rollover = 0; + stream->nb_dts_rollover = 0; } stream->flow_return = GST_FLOW_OK; } @@ -1877,9 +1893,33 @@ gst_ts_demux_record_pts (GstTSDemux * demux, TSDemuxStream * stream, { MpegTSBaseStream *bs = (MpegTSBaseStream *) stream; - GST_LOG ("pid 0x%04x pts:%" GST_TIME_FORMAT " at offset %" - G_GUINT64_FORMAT, bs->pid, - GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (pts)), offset); + GST_LOG ("pid 0x%04x pts:%" G_GUINT64_FORMAT " at offset %" + G_GUINT64_FORMAT, bs->pid, pts, offset); + + if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (stream->pts) && + ABSDIFF (stream->raw_pts, pts) > 900000)) { + /* Detect rollover if diff > 10s */ + GST_LOG ("Detected rollover (previous:%" G_GUINT64_FORMAT " new:%" + G_GUINT64_FORMAT ")", stream->raw_pts, pts); + if (pts < stream->raw_pts) { + /* Forward rollover */ + GST_LOG ("Forward rollover, incrementing nb_pts_rollover"); + stream->nb_pts_rollover++; + } else { + /* Reverse rollover */ + GST_LOG ("Reverse rollover, decrementing nb_pts_rollover"); + stream->nb_pts_rollover--; + } + } + + /* Compute PTS in GstClockTime */ + stream->raw_pts = pts; + stream->pts = + MPEGTIME_TO_GSTTIME (pts + stream->nb_pts_rollover * PTS_DTS_MAX_VALUE); + + GST_LOG ("pid 0x%04x Stored PTS %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")", + bs->pid, stream->raw_pts, GST_TIME_ARGS (stream->pts)); + if (G_UNLIKELY (demux->emit_statistics)) { GstStructure *st; @@ -1899,9 +1939,32 @@ gst_ts_demux_record_dts (GstTSDemux * demux, TSDemuxStream * stream, { MpegTSBaseStream *bs = (MpegTSBaseStream *) stream; - GST_LOG ("pid 0x%04x dts:%" GST_TIME_FORMAT " at offset %" - G_GUINT64_FORMAT, bs->pid, - GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (dts)), offset); + GST_LOG ("pid 0x%04x dts:%" G_GUINT64_FORMAT " at offset %" + G_GUINT64_FORMAT, bs->pid, dts, offset); + + if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (stream->dts) && + ABSDIFF (stream->raw_dts, dts) > 900000)) { + /* Detect rollover if diff > 10s */ + GST_LOG ("Detected rollover (previous:%" G_GUINT64_FORMAT " new:%" + G_GUINT64_FORMAT ")", stream->raw_dts, dts); + if (dts < stream->raw_dts) { + /* Forward rollover */ + GST_LOG ("Forward rollover, incrementing nb_dts_rollover"); + stream->nb_dts_rollover++; + } else { + /* Reverse rollover */ + GST_LOG ("Reverse rollover, decrementing nb_dts_rollover"); + stream->nb_dts_rollover--; + } + } + + /* Compute DTS in GstClockTime */ + stream->raw_dts = dts; + stream->dts = + MPEGTIME_TO_GSTTIME (dts + stream->nb_dts_rollover * PTS_DTS_MAX_VALUE); + + GST_LOG ("pid 0x%04x Stored DTS %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")", + bs->pid, stream->raw_dts, GST_TIME_ARGS (stream->dts)); if (G_UNLIKELY (demux->emit_statistics)) { GstStructure *st; @@ -1952,7 +2015,6 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream) guint8 *data; gsize length; guint64 bufferoffset; - GstClockTime time; PESParsingResult parseres; GstClockTime origts; @@ -1972,6 +2034,9 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream) goto discont; } + if (header.DTS != -1) + gst_ts_demux_record_dts (demux, stream, header.DTS, bufferoffset); + if (header.PTS != -1) { gst_ts_demux_record_pts (demux, stream, header.PTS, bufferoffset); @@ -1995,7 +2060,6 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream) time = calc_gsttime_from_pts (&demux->index_pcr, pts); #endif - stream->pts = time = MPEGTIME_TO_GSTTIME (header.PTS); GST_DEBUG_OBJECT (base, "stream PTS %" GST_TIME_FORMAT " DTS %" GST_TIME_FORMAT, GST_TIME_ARGS (stream->pts), @@ -2050,7 +2114,7 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream) else GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE; } else - GST_BUFFER_TIMESTAMP (buf) = time + base->in_gap; + GST_BUFFER_TIMESTAMP (buf) = stream->pts + base->in_gap; GST_DEBUG ("buf %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); } @@ -2144,7 +2208,7 @@ calculate_and_push_newsegment (GstTSDemux * demux, TSDemuxStream * stream) { MpegTSBase *base = (MpegTSBase *) demux; GstEvent *newsegmentevent; - gint64 start, stop, position; + gint64 start = 0, stop = GST_CLOCK_TIME_NONE, position = 0; GstClockTime firstpts = GST_CLOCK_TIME_NONE; GList *tmp; @@ -2172,24 +2236,27 @@ calculate_and_push_newsegment (GstTSDemux * demux, TSDemuxStream * stream) /* FIXME : We should use base->segment.format and a upstream latency query * to decide if we need to use live values or not */ GST_DEBUG ("push-based. base Segment start:%" GST_TIME_FORMAT " duration:%" - GST_TIME_FORMAT ", time:%" GST_TIME_FORMAT, + GST_TIME_FORMAT ", stop:%" GST_TIME_FORMAT ", time:%" GST_TIME_FORMAT, GST_TIME_ARGS (base->segment.start), GST_TIME_ARGS (base->segment.duration), - GST_TIME_ARGS (base->segment.time)); + GST_TIME_ARGS (base->segment.stop), GST_TIME_ARGS (base->segment.time)); GST_DEBUG ("push-based. demux Segment start:%" GST_TIME_FORMAT " duration:%" - GST_TIME_FORMAT ", time:%" GST_TIME_FORMAT, + GST_TIME_FORMAT ", stop:%" GST_TIME_FORMAT ", time:%" GST_TIME_FORMAT, GST_TIME_ARGS (demux->segment.start), GST_TIME_ARGS (demux->segment.duration), + GST_TIME_ARGS (demux->segment.stop), GST_TIME_ARGS (demux->segment.time)); GST_DEBUG ("stream pts: %" GST_TIME_FORMAT " first pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (stream->pts), GST_TIME_ARGS (firstpts)); - start = base->segment.start; - stop = base->segment.stop; - if (!base->upstream_live) { - /* Shift the start depending on our position in the stream */ - start += firstpts + base->in_gap - base->first_buf_ts; + if (base->segment.format == GST_FORMAT_TIME) { + start = base->segment.start; + stop = base->segment.stop; + if (!base->upstream_live) { + /* Shift the start depending on our position in the stream */ + start += firstpts + base->in_gap - base->first_buf_ts; + } } position = start; } else { diff --git a/gst/videoparsers/gsth264parse.c b/gst/videoparsers/gsth264parse.c index 90916a21e2..98ebc3d21f 100644 --- a/gst/videoparsers/gsth264parse.c +++ b/gst/videoparsers/gsth264parse.c @@ -178,6 +178,7 @@ gst_h264_parse_reset_frame (GstH264Parse * h264parse) /* done parsing; reset state */ h264parse->nalu.valid = FALSE; h264parse->nalu.offset = 0; + h264parse->nalu.sc_offset = 0; h264parse->nalu.size = 0; h264parse->current_off = 0; @@ -213,6 +214,10 @@ gst_h264_parse_reset (GstH264Parse * h264parse) h264parse->have_pps = FALSE; h264parse->have_sps = FALSE; + h264parse->dts = GST_CLOCK_TIME_NONE; + h264parse->ts_trn_nb = GST_CLOCK_TIME_NONE; + h264parse->do_ts = TRUE; + h264parse->pending_key_unit_ts = GST_CLOCK_TIME_NONE; h264parse->force_key_unit_event = NULL; @@ -319,7 +324,7 @@ gst_h264_parse_format_from_caps (GstCaps * caps, guint * format, guint * align) /* check downstream caps to configure format and alignment */ static void -gst_h264_parse_negotiate (GstH264Parse * h264parse) +gst_h264_parse_negotiate (GstH264Parse * h264parse, GstCaps * in_caps) { GstCaps *caps; guint format = GST_H264_PARSE_FORMAT_NONE; @@ -328,10 +333,19 @@ gst_h264_parse_negotiate (GstH264Parse * h264parse) caps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (h264parse)); GST_DEBUG_OBJECT (h264parse, "allowed caps: %" GST_PTR_FORMAT, caps); - gst_h264_parse_format_from_caps (caps, &format, &align); + if (in_caps && caps) { + if (gst_caps_can_intersect (in_caps, caps)) { + GST_DEBUG_OBJECT (h264parse, "downstream accepts upstream caps"); + gst_h264_parse_format_from_caps (in_caps, &format, &align); + gst_caps_unref (caps); + caps = NULL; + } + } - if (caps) + if (caps) { + gst_h264_parse_format_from_caps (caps, &format, &align); gst_caps_unref (caps); + } /* default */ if (!format) @@ -618,7 +632,7 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse, guint current_off = 0; gboolean drain; GstH264NalParser *nalparser = h264parse->nalparser; - GstH264NalUnit nalu = h264parse->nalu; + GstH264NalUnit nalu; data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ); @@ -630,7 +644,7 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse, /* need to configure aggregation */ if (G_UNLIKELY (h264parse->format == GST_H264_PARSE_FORMAT_NONE)) - gst_h264_parse_negotiate (h264parse); + gst_h264_parse_negotiate (h264parse, NULL); /* avoid stale cached parsing state */ if (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_PARSING)) { @@ -642,6 +656,7 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse, } drain = FALSE; + nalu = h264parse->nalu; current_off = h264parse->current_off; GST_DEBUG_OBJECT (h264parse, "last parse position %u", current_off); @@ -686,7 +701,9 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse, current_off = size - 3; goto parsing_error; case GST_H264_PARSER_NO_NAL: - current_off = size - 3; + /* don't expect to have found any NAL so far */ + g_assert (h264parse->nalu.size == 0); + current_off = h264parse->nalu.sc_offset = size - 3; goto more; case GST_H264_PARSER_BROKEN_DATA: GST_WARNING_OBJECT (h264parse, "input stream is corrupt; " @@ -1063,7 +1080,7 @@ gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps) /* but not necessarily or reliably this */ if (h264parse->fps_num > 0 && h264parse->fps_den > 0) gst_caps_set_simple (caps, "framerate", - GST_TYPE_FRACTION, sps->fps_num, sps->fps_den, NULL); + GST_TYPE_FRACTION, h264parse->fps_num, h264parse->fps_den, NULL); } } @@ -1243,9 +1260,12 @@ gst_h264_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) gst_h264_parse_update_src_caps (h264parse, NULL); - gst_h264_parse_get_timestamp (h264parse, - &GST_BUFFER_TIMESTAMP (buffer), &GST_BUFFER_DURATION (buffer), - h264parse->frame_start); + /* don't mess with timestamps if provided by upstream, + * particularly since our ts not that good they handle seeking etc */ + if (h264parse->do_ts) + gst_h264_parse_get_timestamp (h264parse, + &GST_BUFFER_TIMESTAMP (buffer), &GST_BUFFER_DURATION (buffer), + h264parse->frame_start); if (h264parse->keyframe) GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); @@ -1476,6 +1496,9 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) new_buf = gst_byte_writer_reset_and_get_buffer (&bw); gst_buffer_copy_into (new_buf, buffer, GST_BUFFER_COPY_METADATA, 0, -1); + /* should already be keyframe/IDR, but it may not have been, + * so mark it as such to avoid being discarded by picky decoder */ + GST_BUFFER_FLAG_UNSET (new_buf, GST_BUFFER_FLAG_DELTA_UNIT); gst_buffer_replace (&frame->buffer, new_buf); gst_buffer_unref (new_buf); } @@ -1614,8 +1637,20 @@ gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps) } } - /* negotiate with downstream, sets ->format and ->align */ - gst_h264_parse_negotiate (h264parse); + { + GstCaps *in_caps; + + /* prefer input type determined above */ + in_caps = gst_caps_new_simple ("video/x-h264", + "parsed", G_TYPE_BOOLEAN, TRUE, + "stream-format", G_TYPE_STRING, + gst_h264_parse_get_string (h264parse, TRUE, format), + "alignment", G_TYPE_STRING, + gst_h264_parse_get_string (h264parse, FALSE, align), NULL); + /* negotiate with downstream, sets ->format and ->align */ + gst_h264_parse_negotiate (h264parse, in_caps); + gst_caps_unref (in_caps); + } if (format == h264parse->format && align == h264parse->align) { gst_base_parse_set_passthrough (parse, TRUE); @@ -1732,6 +1767,22 @@ gst_h264_parse_event (GstBaseParse * parse, GstEvent * event) gst_event_replace (&h264parse->force_key_unit_event, event); break; } + case GST_EVENT_FLUSH_STOP: + h264parse->dts = GST_CLOCK_TIME_NONE; + h264parse->ts_trn_nb = GST_CLOCK_TIME_NONE; + break; + case GST_EVENT_SEGMENT: + { + const GstSegment *segment; + + gst_event_parse_segment (event, &segment); + /* don't try to mess with more subtle cases (e.g. seek) */ + if (segment->format == GST_FORMAT_TIME && + (segment->start != 0 || segment->rate != 1.0 + || segment->applied_rate != 1.0)) + h264parse->do_ts = FALSE; + break; + } default: break; } diff --git a/gst/videoparsers/gsth264parse.h b/gst/videoparsers/gsth264parse.h index 4800092b39..1064ff8bba 100644 --- a/gst/videoparsers/gsth264parse.h +++ b/gst/videoparsers/gsth264parse.h @@ -92,6 +92,7 @@ struct _GstH264Parse GstClockTime dts; /* dts at start of last buffering period */ GstClockTime ts_trn_nb; + gboolean do_ts; /* frame parsing */ /*guint last_nal_pos;*/ diff --git a/gst/videoparsers/gstmpegvideoparse.c b/gst/videoparsers/gstmpegvideoparse.c index 21595407c4..6f7cb7cb03 100644 --- a/gst/videoparsers/gstmpegvideoparse.c +++ b/gst/videoparsers/gstmpegvideoparse.c @@ -642,12 +642,13 @@ gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse) * 3 => SNR Scalable, 4 => Main, 5 => Simple * 4:2:2 and Multi-view have profile = 0, with the escape bit set to 1 */ - const gchar *profiles[] = { "high", "spatial", "snr", "main", "simple" }; + const gchar *const profiles[] = + { "high", "spatial", "snr", "main", "simple" }; /* * Level indication - 4 => High, 6 => High-1440, 8 => Main, 10 => Low, * except in the case of profile = 0 */ - const gchar *levels[] = { "high", "high-1440", "main", "low" }; + const gchar *const levels[] = { "high", "high-1440", "main", "low" }; if (profile_c > 0 && profile_c < 6) profile = profiles[profile_c - 1]; diff --git a/tests/check/elements/camerabin.c b/tests/check/elements/camerabin.c index 53a82e9f5b..ce17ac3e3a 100644 --- a/tests/check/elements/camerabin.c +++ b/tests/check/elements/camerabin.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -501,6 +502,16 @@ check_file_validity (const gchar * filename, gint num, GstTagList * taglist) return TRUE; } +static void +remove_file (const gchar * fn_template, guint num) +{ + const gchar *fn; + + fn = make_test_file_name (fn_template, num); + GST_INFO ("removing %s", fn); + g_unlink (fn); +} + GST_START_TEST (test_single_image_capture) { gboolean ready = FALSE; @@ -544,6 +555,7 @@ GST_START_TEST (test_single_image_capture) gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); check_file_validity (SINGLE_IMAGE_FILENAME, 0, NULL); + remove_file (SINGLE_IMAGE_FILENAME, 0); } GST_END_TEST; @@ -568,6 +580,7 @@ GST_START_TEST (test_single_image_capture_with_flags) gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); check_file_validity (SINGLE_IMAGE_WITH_FLAGS_FILENAME, 0, NULL); + remove_file (SINGLE_IMAGE_WITH_FLAGS_FILENAME, 0); } GST_END_TEST; @@ -617,6 +630,7 @@ GST_START_TEST (test_video_recording) gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); check_file_validity (VIDEO_WITH_FLAGS_FILENAME, 0, NULL); + remove_file (VIDEO_WITH_FLAGS_FILENAME, 0); } GST_END_TEST; @@ -653,6 +667,7 @@ GST_START_TEST (test_video_recording_with_flags) gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); check_file_validity (VIDEO_FILENAME, 0, NULL); + remove_file (VIDEO_FILENAME, 0); } GST_END_TEST; @@ -704,6 +719,7 @@ GST_START_TEST (test_video_recording_pause) gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); check_file_validity (VIDEO_PAUSE_FILENAME, 0, NULL); + remove_file (VIDEO_PAUSE_FILENAME, 0); } GST_END_TEST; @@ -740,6 +756,7 @@ GST_START_TEST (test_video_recording_no_audio) gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); check_file_validity (VIDEO_NOAUDIO_FILENAME, 0, NULL); + remove_file (VIDEO_NOAUDIO_FILENAME, 0); } GST_END_TEST; @@ -767,7 +784,9 @@ GST_START_TEST (test_image_video_cycle) /* validate all the files */ for (i = 2; i > 0; i--) { check_file_validity (CYCLE_IMAGE_FILENAME, i, NULL); + remove_file (CYCLE_IMAGE_FILENAME, i); check_file_validity (CYCLE_VIDEO_FILENAME, i, NULL); + remove_file (CYCLE_VIDEO_FILENAME, i); } } @@ -796,6 +815,7 @@ GST_START_TEST (test_image_tags_setting) for (i = 0; i < SEQUENTIAL_IMAGES_COUNT; i++) { check_file_validity (SEQUENTIAL_IMAGES_FILENAME, i, taglists[i % TAGLISTS_COUNT]); + remove_file (SEQUENTIAL_IMAGES_FILENAME, i); } } diff --git a/tests/check/elements/camerabin2.c b/tests/check/elements/camerabin2.c index efdd977f03..7d9513f958 100644 --- a/tests/check/elements/camerabin2.c +++ b/tests/check/elements/camerabin2.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -450,8 +451,9 @@ teardown (void) tags_found = NULL; g_free (video_filename); - g_free (image_filename); video_filename = NULL; + + g_free (image_filename); image_filename = NULL; GST_INFO ("done"); @@ -585,6 +587,16 @@ check_file_validity (const gchar * filename, gint num, GstTagList * taglist, return TRUE; } +static void +remove_file (const gchar * fn_template, guint num) +{ + const gchar *fn; + + fn = make_const_file_name (fn_template, num); + GST_INFO ("removing %s", fn); + g_unlink (fn); +} + static GstPadProbeReturn filter_buffer_count (GstPad * pad, GstPadProbeInfo * info, gpointer data) { @@ -692,6 +704,7 @@ GST_START_TEST (test_single_image_capture) wait_for_idle_state (); gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); check_file_validity (image_filename, 0, NULL, 0, 0, NO_AUDIO); + remove_file (image_filename, 0); } GST_END_TEST; @@ -746,6 +759,7 @@ GST_START_TEST (test_multiple_image_captures) for (i = 0; i < 3; i++) { check_file_validity (image_filename, i, NULL, widths[i], heights[i], NO_AUDIO); + remove_file (image_filename, i); } } @@ -795,6 +809,8 @@ GST_START_TEST (test_single_video_recording) gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); check_file_validity (video_filename, 0, NULL, 0, 0, WITH_AUDIO); + remove_file (video_filename, 0); + } GST_END_TEST; @@ -866,6 +882,7 @@ GST_START_TEST (test_multiple_video_recordings) for (i = 0; i < 3; i++) { check_file_validity (video_filename, i, NULL, widths[i], heights[i], WITH_AUDIO); + remove_file (video_filename, i); } } @@ -930,7 +947,9 @@ GST_START_TEST (test_image_video_cycle) /* validate all the files */ for (i = 0; i < 2; i++) { check_file_validity (image_filename, i, NULL, 0, 0, NO_AUDIO); + remove_file (image_filename, i); check_file_validity (video_filename, i, NULL, 0, 0, WITH_AUDIO); + remove_file (video_filename, i); } } @@ -977,6 +996,7 @@ GST_START_TEST (test_image_capture_previews) gst_message_unref (msg); check_preview_image (camera, image_filename, i); + remove_file (image_filename, i); if (preview_buffer) gst_buffer_unref (preview_buffer); @@ -1056,6 +1076,7 @@ GST_START_TEST (test_image_capture_with_tags) for (i = 0; i < 3; i++) { check_file_validity (image_filename, i, taglists[i], 0, 0, NO_AUDIO); gst_tag_list_free (taglists[i]); + remove_file (image_filename, i); } } @@ -1133,6 +1154,7 @@ GST_START_TEST (test_video_capture_with_tags) for (i = 0; i < 3; i++) { check_file_validity (video_filename, i, taglists[i], 0, 0, NO_AUDIO); gst_tag_list_free (taglists[i]); + remove_file (video_filename, i); } } @@ -1234,6 +1256,7 @@ GST_START_TEST (test_idle_property) gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); check_file_validity (video_filename, 0, NULL, 0, 0, WITH_AUDIO); + remove_file (video_filename, 0); } GST_END_TEST; @@ -1300,6 +1323,7 @@ GST_START_TEST (test_image_custom_filter) gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); check_file_validity (image_filename, 0, NULL, 0, 0, NO_AUDIO); + remove_file (image_filename, 0); fail_unless (vf_probe_counter > 0); fail_unless (image_probe_counter == 1); @@ -1381,6 +1405,7 @@ GST_START_TEST (test_video_custom_filter) gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); check_file_validity (video_filename, 0, NULL, 0, 0, WITH_AUDIO); + remove_file (video_filename, 0); fail_unless (vf_probe_counter > 0); fail_unless (video_probe_counter > 0); @@ -1483,6 +1508,7 @@ GST_START_TEST (test_image_location_switching) } for (i = 0; i < LOCATION_SWITCHING_FILENAMES_COUNT; i++) { + g_unlink (filenames[i]); g_free (filenames[i]); } g_signal_handler_disconnect (src, notify_id); diff --git a/tests/check/elements/jifmux.c b/tests/check/elements/jifmux.c index 9e21d1a5b0..05e67561f0 100644 --- a/tests/check/elements/jifmux.c +++ b/tests/check/elements/jifmux.c @@ -27,6 +27,8 @@ #include #include +#include + #include #include @@ -1200,6 +1202,7 @@ GST_START_TEST (test_jifmux_tags) tmpfile); libexif_check_tags (FILE_SOURCE_TAG ("transparent-scanner"), tmpfile); + g_unlink (tmpfile); g_free (tmpfile); } diff --git a/tests/examples/camerabin2/gst-camera2.c b/tests/examples/camerabin2/gst-camera2.c index a6610c856b..6a59b47d93 100644 --- a/tests/examples/camerabin2/gst-camera2.c +++ b/tests/examples/camerabin2/gst-camera2.c @@ -257,9 +257,10 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) return TRUE; } -static void +static gboolean init_gtkwidgets_data (void) { +#if GTK_CHECK_VERSION(2,24,0) gint i; GtkComboBoxText *combobox = GTK_COMBO_BOX_TEXT (gtk_builder_get_object (builder, "formatComboBox")); @@ -273,6 +274,11 @@ init_gtkwidgets_data (void) /* default to the first one -> ogg */ gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0); + return TRUE; +#else + g_warning ("This needs a newer version of GTK (2.24 at least)"); + return FALSE; +#endif } int @@ -298,7 +304,9 @@ main (int argc, char *argv[]) gst_bus_set_sync_handler (bus, bus_sync_callback, NULL); gst_object_unref (bus); - init_gtkwidgets_data (); + if (!init_gtkwidgets_data ()) { + goto error; + } ui_main_window = GTK_WIDGET (gtk_builder_get_object (builder, "mainWindow")); gtk_builder_connect_signals (builder, NULL); @@ -308,6 +316,7 @@ main (int argc, char *argv[]) gtk_main (); +error: gst_element_set_state (camera, GST_STATE_NULL); gst_object_unref (camera); return ret;