Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Deniz Ugur, Romain Bouqueau, Sohaib Larbi
5 : * Copyright (c) Motion Spell
6 : * All rights reserved
7 : *
8 : * This file is part of the GPAC/GStreamer wrapper
9 : *
10 : * This GPAC/GStreamer wrapper is free software; you can redistribute it
11 : * and/or modify it under the terms of the GNU Affero General Public License
12 : * as published by the Free Software Foundation; either version 3, or (at
13 : * your option) any later version.
14 : *
15 : * This GPAC/GStreamer wrapper is distributed in the hope that it will be
16 : * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Affero General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Affero General Public
21 : * License along with this library; see the file LICENSE. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include "lib/packet.h"
27 : #include "conversion/packet/registry.h"
28 : #include "utils.h"
29 :
30 : static void
31 6524 : gpac_pck_destructor(GF_Filter* filter, GF_FilterPid* PID, GF_FilterPacket* pck)
32 : {
33 : const GF_PropertyValue* prop =
34 6524 : gf_filter_pck_get_property(pck, GF_PROP_PCK_UDTA);
35 6524 : if (prop) {
36 6524 : GstBuffer* buffer = prop->value.ptr;
37 6524 : gst_buffer_unref(buffer);
38 : }
39 6524 : }
40 :
41 : guint64
42 13048 : gpac_pck_get_stream_time(GstClockTime time,
43 : GpacPadPrivate* priv,
44 : gboolean is_dts)
45 : {
46 13048 : GstElement* element = gst_pad_get_parent_element(priv->self);
47 13048 : if (!GST_CLOCK_TIME_IS_VALID(time))
48 0 : goto fail;
49 :
50 : // Identity if segment isn't time based
51 13048 : if (!priv->segment || priv->segment->format != GST_FORMAT_TIME)
52 0 : return time;
53 :
54 : guint64 unsigned_time;
55 13048 : int ret = gst_segment_to_stream_time_full(
56 13048 : priv->segment, GST_FORMAT_TIME, time, &unsigned_time);
57 13048 : if (ret == 0)
58 0 : goto fail;
59 :
60 : // It's possible that DTS is negative, so we need to offset it with the
61 : // DTS value
62 13048 : gboolean is_negative = ret < 0;
63 13048 : if (is_dts && is_negative && !priv->dts_offset_set) {
64 8 : priv->dts_offset = (gint64)unsigned_time;
65 8 : priv->dts_offset_set = TRUE;
66 : }
67 :
68 : // Offset the time with the initial DTS offset
69 13048 : if (is_dts) {
70 6524 : if (is_negative) {
71 16 : unsigned_time = priv->dts_offset - unsigned_time;
72 : } else {
73 6508 : unsigned_time = priv->dts_offset + unsigned_time;
74 : }
75 6524 : } else if (is_negative) {
76 0 : GST_ELEMENT_WARNING(element,
77 : STREAM,
78 : FAILED,
79 : ("PTS %" GST_TIME_FORMAT
80 : " is not valid, likely not related to current segment",
81 : GST_TIME_ARGS(time)),
82 : (NULL));
83 : }
84 :
85 13048 : return unsigned_time;
86 :
87 0 : fail:
88 0 : GST_ELEMENT_ERROR(element,
89 : STREAM,
90 : FAILED,
91 : ("Failed to convert time %" GST_TIME_FORMAT
92 : " to stream time",
93 : GST_TIME_ARGS(time)),
94 : (NULL));
95 0 : return 0;
96 : }
97 :
98 : void
99 4637 : gpac_configure_video(GstBuffer* buffer,
100 : GpacPadPrivate* priv,
101 : GF_FilterPacket* packet)
102 : {
103 : // Decide on sample dependency flags
104 4637 : gboolean is_delta =
105 4637 : GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
106 4637 : gboolean is_droppable =
107 4637 : GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DROPPABLE);
108 4637 : gboolean is_discontinuity =
109 4637 : GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT);
110 :
111 : // Set the SAP type for video streams
112 4637 : gf_filter_pck_set_sap(packet,
113 : is_delta ? GF_FILTER_SAP_NONE : GF_FILTER_SAP_1);
114 :
115 : // Note that acceptance tests doesn't like SAP, is_leading, sample_depends_on
116 4637 : u32 flags = 0;
117 :
118 : // is_leading
119 4637 : if (is_delta)
120 4538 : flags |= (priv->last_frame_was_keyframe ? 3 : 2) << 6;
121 :
122 : // sample_depends_on
123 4637 : if (is_discontinuity)
124 17 : flags |= 2 << 4;
125 : else
126 4620 : flags |= ((is_delta ? 1 : 2) << 4);
127 :
128 4637 : flags |= ((is_droppable ? 2 : 1) << 2); // sample_is_depended_on
129 4637 : flags |= (2 << 0); // sample_has_redundancy
130 :
131 4637 : gf_filter_pck_set_dependency_flags(packet, flags);
132 4637 : priv->last_frame_was_keyframe = !is_delta;
133 4637 : }
134 :
135 : void
136 6524 : gpac_pck_prop_configure(GPAC_PCK_PROP_IMPL_ARGS)
137 : {
138 : // Check arguments
139 6524 : g_return_if_fail(buffer != NULL);
140 6524 : g_return_if_fail(priv != NULL);
141 6524 : g_return_if_fail(pck != NULL);
142 :
143 : // Go through the property registry
144 13048 : for (u32 i = 0; i < gpac_pck_get_num_supported_props(); i++) {
145 6524 : prop_registry_entry* entry = &prop_registry[i];
146 :
147 : // Run the handler for the property
148 6524 : entry->handler(buffer, priv, pck, pid);
149 : }
150 : }
151 :
152 : GF_FilterPacket*
153 6524 : gpac_pck_new_from_buffer(GstBuffer* buffer,
154 : GpacPadPrivate* priv,
155 : GF_FilterPid* pid)
156 : {
157 : const GF_PropertyValue* p;
158 6524 : GstElement* element = gst_pad_get_parent_element(priv->self);
159 :
160 : // Map the buffer
161 6524 : g_auto(GstBufferMapInfo) map = GST_MAP_INFO_INIT;
162 6524 : if (G_UNLIKELY(!gst_buffer_map(buffer, &map, GST_MAP_READ))) {
163 0 : GST_ELEMENT_ERROR(
164 : element, STREAM, FAILED, (NULL), ("Failed to map buffer"));
165 0 : return NULL;
166 : }
167 :
168 : // Create a new shared packet
169 : GF_FilterPacket* packet =
170 6524 : gf_filter_pck_new_shared(pid, map.data, map.size, gpac_pck_destructor);
171 :
172 : // Ref the buffer so that we can free it later
173 6524 : GstBuffer* ref = gst_buffer_ref(buffer);
174 : GF_Err err =
175 6524 : gf_filter_pck_set_property(packet, GF_PROP_PCK_UDTA, &PROP_POINTER(ref));
176 6524 : if (G_UNLIKELY(err != GF_OK)) {
177 0 : GST_ELEMENT_ERROR(element,
178 : STREAM,
179 : FAILED,
180 : (NULL),
181 : ("Failed to save the buffer ref to the packet"));
182 0 : gst_buffer_unref(ref);
183 0 : gf_filter_pck_unref(packet);
184 0 : return NULL;
185 : }
186 :
187 : // Get the fps from the PID
188 6524 : GF_Fraction fps = { 1, 1 };
189 6524 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
190 6524 : if (p)
191 4637 : fps = p->value.frac;
192 :
193 : // Get the timescale from the PID
194 6524 : guint64 timescale = GST_SECOND;
195 6524 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
196 6524 : if (p)
197 6524 : timescale = p->value.uint;
198 :
199 : // Set the DTS to DTS or PTS, whichever is valid
200 6524 : if (GST_BUFFER_DTS_IS_VALID(buffer) || GST_BUFFER_PTS_IS_VALID(buffer)) {
201 : guint64 dts =
202 6524 : gpac_pck_get_stream_time(GST_BUFFER_DTS_OR_PTS(buffer), priv, TRUE);
203 6524 : dts = gpac_time_rescale_with_fps(dts, fps, timescale);
204 6524 : gf_filter_pck_set_dts(packet, dts);
205 : }
206 :
207 : // Set the CTS to PTS if it's valid
208 6524 : if (GST_BUFFER_PTS_IS_VALID(buffer)) {
209 6524 : guint64 cts = gpac_pck_get_stream_time(GST_BUFFER_PTS(buffer), priv, FALSE);
210 6524 : cts = gpac_time_rescale_with_fps(cts, fps, timescale);
211 6524 : gf_filter_pck_set_cts(packet, cts);
212 : }
213 :
214 : // Set the duration
215 6524 : if (GST_BUFFER_DURATION_IS_VALID(buffer)) {
216 6524 : guint64 duration = GST_BUFFER_DURATION(buffer);
217 6524 : duration = gpac_time_rescale_with_fps(duration, fps, timescale);
218 6524 : gf_filter_pck_set_duration(packet, duration);
219 : }
220 :
221 : // Set packet framing
222 6524 : gf_filter_pck_set_framing(packet, GF_TRUE, GF_TRUE);
223 :
224 : // Set the default SAP type
225 6524 : gf_filter_pck_set_sap(packet, GF_FILTER_SAP_1);
226 :
227 : // Check if this is a video
228 : const GF_PropertyValue* p_typ =
229 6524 : gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
230 6524 : gboolean is_video = p_typ && p_typ->value.uint == GF_STREAM_VISUAL;
231 :
232 : // For video streams, we need further configuration
233 6524 : if (is_video) {
234 4637 : gpac_configure_video(buffer, priv, packet);
235 : }
236 :
237 : // Configure the packet properties
238 6524 : gpac_pck_prop_configure(buffer, priv, packet, pid);
239 :
240 6524 : return packet;
241 : }
|