• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  *
3  * Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include <gst/gst.h>
25 #include <gst/check/gstcheck.h>
26 #include <gst/check/gstharness.h>
27 #include <gst/video/video.h>
28 
29 #include <string.h>
30 
31 static GstStaticCaps foo_bar_caps = GST_STATIC_CAPS ("foo/bar");
32 static GstStaticCaps cea708_cc_data_caps =
33 GST_STATIC_CAPS ("closedcaption/x-cea-708,format=(string) cc_data");
34 
GST_START_TEST(no_captions)35 GST_START_TEST (no_captions)
36 {
37   GstHarness *h;
38   GstBuffer *buf, *outbuf;
39   GstCaps *caps;
40 
41   h = gst_harness_new_with_padnames ("cccombiner", "sink", "src");
42 
43   gst_harness_set_src_caps_str (h, foo_bar_caps.string);
44 
45   buf = gst_buffer_new_and_alloc (128);
46   GST_BUFFER_PTS (buf) = 0;
47   GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
48   outbuf = gst_harness_push_and_pull (h, gst_buffer_ref (buf));
49 
50   fail_unless (outbuf != NULL);
51   fail_unless (outbuf == buf);
52 
53   caps = gst_pad_get_current_caps (h->sinkpad);
54   fail_unless (caps != NULL);
55   fail_unless (gst_caps_can_intersect (caps,
56           gst_static_caps_get (&foo_bar_caps)));
57   gst_caps_unref (caps);
58 
59   gst_buffer_unref (buf);
60   gst_buffer_unref (outbuf);
61 
62   gst_harness_teardown (h);
63 }
64 
65 GST_END_TEST;
66 
67 GstBuffer *expected_video_buffer = NULL;
68 GstBuffer *expected_caption_buffer = NULL;
69 
70 static void
samples_selected_cb(GstAggregator * agg,GstSegment * segment,GstClockTime pts,GstClockTime dts,GstClockTime duration,GstStructure * info,gpointer user_data)71 samples_selected_cb (GstAggregator * agg, GstSegment * segment,
72     GstClockTime pts, GstClockTime dts, GstClockTime duration,
73     GstStructure * info, gpointer user_data)
74 {
75   GstBufferList *buflist;
76   GstPad *caption_pad =
77       gst_element_get_static_pad (GST_ELEMENT (agg), "caption");
78   GstPad *video_pad = gst_element_get_static_pad (GST_ELEMENT (agg), "sink");
79   GstSample *video_sample =
80       gst_aggregator_peek_next_sample (agg, GST_AGGREGATOR_PAD (video_pad));
81   GstSample *captions_sample =
82       gst_aggregator_peek_next_sample (agg, GST_AGGREGATOR_PAD (caption_pad));
83 
84   fail_unless (video_sample != NULL);
85   fail_unless (captions_sample != NULL);
86 
87   fail_unless (gst_sample_get_buffer (video_sample) == expected_video_buffer);
88   gst_sample_unref (video_sample);
89 
90   buflist = gst_sample_get_buffer_list (captions_sample);
91   fail_unless_equals_int (gst_buffer_list_length (buflist), 1);
92   gst_sample_unref (captions_sample);
93 
94   gst_object_unref (caption_pad);
95   gst_object_unref (video_pad);
96 }
97 
GST_START_TEST(captions_and_eos)98 GST_START_TEST (captions_and_eos)
99 {
100   GstHarness *h, *h2;
101   GstBuffer *buf, *outbuf;
102   GstPad *caption_pad;
103   GstCaps *caps;
104   GstVideoCaptionMeta *meta;
105   GstBuffer *second_video_buf, *second_caption_buf;
106   const guint8 cc_data[3] = { 0xfc, 0x20, 0x20 };
107 
108   h = gst_harness_new_with_padnames ("cccombiner", "sink", "src");
109   h2 = gst_harness_new_with_element (h->element, NULL, NULL);
110   caption_pad = gst_element_request_pad_simple (h->element, "caption");
111   gst_harness_add_element_sink_pad (h2, caption_pad);
112   gst_object_unref (caption_pad);
113 
114   g_object_set (h->element, "emit-signals", TRUE, NULL);
115   g_signal_connect (h->element, "samples-selected",
116       G_CALLBACK (samples_selected_cb), NULL);
117 
118   gst_harness_set_src_caps_str (h, foo_bar_caps.string);
119   gst_harness_set_src_caps_str (h2, cea708_cc_data_caps.string);
120 
121   /* Push a buffer and caption buffer */
122   buf = gst_buffer_new_and_alloc (128);
123   GST_BUFFER_PTS (buf) = 0;
124   GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
125   expected_video_buffer = buf;
126   gst_harness_push (h, buf);
127 
128   buf = gst_buffer_new_and_alloc (3);
129   gst_buffer_fill (buf, 0, cc_data, 3);
130   GST_BUFFER_PTS (buf) = 0;
131   GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
132   expected_caption_buffer = buf;
133   gst_harness_push (h2, buf);
134 
135   /* And another one: the first video buffer should be retrievable
136    * after the second caption buffer is pushed */
137   buf = gst_buffer_new_and_alloc (128);
138   GST_BUFFER_PTS (buf) = 40 * GST_MSECOND;
139   GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
140   second_video_buf = buf;
141   gst_harness_push (h, buf);
142 
143   buf = gst_buffer_new_and_alloc (3);
144   gst_buffer_fill (buf, 0, cc_data, 3);
145   GST_BUFFER_PTS (buf) = 40 * GST_MSECOND;
146   GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
147   second_caption_buf = buf;
148   gst_harness_push (h2, buf);
149 
150   /* Pull the first output buffer */
151   outbuf = gst_harness_pull (h);
152   fail_unless (outbuf != NULL);
153 
154   expected_video_buffer = second_video_buf;
155   expected_caption_buffer = second_caption_buf;
156 
157   meta = gst_buffer_get_video_caption_meta (outbuf);
158   fail_unless (meta != NULL);
159   fail_unless_equals_int (meta->caption_type,
160       GST_VIDEO_CAPTION_TYPE_CEA708_RAW);
161   fail_unless_equals_int (meta->size, 3);
162 
163   gst_buffer_unref (outbuf);
164 
165   /* Push EOS on both pads get the second output buffer, we otherwise wait
166    * in case there are further captions for the current video buffer */
167   gst_harness_push_event (h, gst_event_new_eos ());
168   gst_harness_push_event (h2, gst_event_new_eos ());
169 
170   outbuf = gst_harness_pull (h);
171   fail_unless (outbuf != NULL);
172 
173   meta = gst_buffer_get_video_caption_meta (outbuf);
174   fail_unless (meta != NULL);
175   fail_unless_equals_int (meta->caption_type,
176       GST_VIDEO_CAPTION_TYPE_CEA708_RAW);
177   fail_unless_equals_int (meta->size, 3);
178 
179   gst_buffer_unref (outbuf);
180 
181   /* Caps should be equal to input caps */
182   caps = gst_pad_get_current_caps (h->sinkpad);
183   fail_unless (caps != NULL);
184   fail_unless (gst_caps_can_intersect (caps,
185           gst_static_caps_get (&foo_bar_caps)));
186   gst_caps_unref (caps);
187 
188   gst_harness_teardown (h);
189   gst_harness_teardown (h2);
190 }
191 
192 GST_END_TEST;
193 
194 static Suite *
cccombiner_suite(void)195 cccombiner_suite (void)
196 {
197   Suite *s = suite_create ("cccombiner");
198   TCase *tc = tcase_create ("general");
199 
200   suite_add_tcase (s, tc);
201 
202   tcase_add_test (tc, no_captions);
203   tcase_add_test (tc, captions_and_eos);
204 
205   return s;
206 }
207 
208 GST_CHECK_MAIN (cccombiner);
209