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 : guint64 unsigned_time;
51 13048 : int ret = gst_segment_to_stream_time_full(
52 13048 : priv->segment, GST_FORMAT_TIME, time, &unsigned_time);
53 13048 : if (ret == 0)
54 0 : goto fail;
55 :
56 : // It's possible that DTS is negative, so we need to offset it with the
57 : // DTS value
58 13048 : gboolean is_negative = ret < 0;
59 13048 : if (is_dts && is_negative && !priv->dts_offset_set) {
60 8 : priv->dts_offset = (gint64)unsigned_time;
61 8 : priv->dts_offset_set = TRUE;
62 : }
63 :
64 : // Offset the time with the initial DTS offset
65 13048 : if (is_dts) {
66 6524 : if (is_negative) {
67 16 : unsigned_time = priv->dts_offset - unsigned_time;
68 : } else {
69 6508 : unsigned_time = priv->dts_offset + unsigned_time;
70 : }
71 6524 : } else if (is_negative) {
72 0 : GST_ELEMENT_WARNING(element,
73 : STREAM,
74 : FAILED,
75 : ("PTS %" GST_TIME_FORMAT
76 : " is not valid, likely not related to current segment",
77 : GST_TIME_ARGS(time)),
78 : (NULL));
79 : }
80 :
81 13048 : return unsigned_time;
82 :
83 0 : fail:
84 0 : GST_ELEMENT_ERROR(element,
85 : STREAM,
86 : FAILED,
87 : ("Failed to convert time %" GST_TIME_FORMAT
88 : " to stream time",
89 : GST_TIME_ARGS(time)),
90 : (NULL));
91 0 : return 0;
92 : }
93 :
94 : void
95 4637 : gpac_configure_video(GstBuffer* buffer,
96 : GpacPadPrivate* priv,
97 : GF_FilterPacket* packet)
98 : {
99 : // Decide on sample dependency flags
100 4637 : gboolean is_delta =
101 4637 : GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
102 4637 : gboolean is_droppable =
103 4637 : GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DROPPABLE);
104 4637 : gboolean is_discontinuity =
105 4637 : GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT);
106 :
107 : // Set the SAP type for video streams
108 4637 : gf_filter_pck_set_sap(packet,
109 : is_delta ? GF_FILTER_SAP_NONE : GF_FILTER_SAP_1);
110 :
111 : // Note that acceptance tests doesn't like SAP, is_leading, sample_depends_on
112 4637 : u32 flags = 0;
113 :
114 : // is_leading
115 4637 : if (is_delta)
116 4538 : flags |= (priv->last_frame_was_keyframe ? 3 : 2) << 6;
117 :
118 : // sample_depends_on
119 4637 : if (is_discontinuity)
120 17 : flags |= 2 << 4;
121 : else
122 4620 : flags |= ((is_delta ? 1 : 2) << 4);
123 :
124 4637 : flags |= ((is_droppable ? 2 : 1) << 2); // sample_is_depended_on
125 4637 : flags |= (2 << 0); // sample_has_redundancy
126 :
127 4637 : gf_filter_pck_set_dependency_flags(packet, flags);
128 4637 : priv->last_frame_was_keyframe = !is_delta;
129 4637 : }
130 :
131 : void
132 6524 : gpac_pck_prop_configure(GPAC_PCK_PROP_IMPL_ARGS)
133 : {
134 : // Check arguments
135 6524 : g_return_if_fail(buffer != NULL);
136 6524 : g_return_if_fail(priv != NULL);
137 6524 : g_return_if_fail(pck != NULL);
138 :
139 : // Go through the property registry
140 13048 : for (u32 i = 0; i < gpac_pck_get_num_supported_props(); i++) {
141 6524 : prop_registry_entry* entry = &prop_registry[i];
142 :
143 : // Run the handler for the property
144 6524 : entry->handler(buffer, priv, pck, pid);
145 : }
146 : }
147 :
148 : GF_FilterPacket*
149 6524 : gpac_pck_new_from_buffer(GstBuffer* buffer,
150 : GpacPadPrivate* priv,
151 : GF_FilterPid* pid)
152 : {
153 : const GF_PropertyValue* p;
154 6524 : GstElement* element = gst_pad_get_parent_element(priv->self);
155 :
156 : // Map the buffer
157 6524 : g_auto(GstBufferMapInfo) map = GST_MAP_INFO_INIT;
158 6524 : if (G_UNLIKELY(!gst_buffer_map(buffer, &map, GST_MAP_READ))) {
159 0 : GST_ELEMENT_ERROR(
160 : element, STREAM, FAILED, (NULL), ("Failed to map buffer"));
161 0 : return NULL;
162 : }
163 :
164 : // Create a new shared packet
165 : GF_FilterPacket* packet =
166 6524 : gf_filter_pck_new_shared(pid, map.data, map.size, gpac_pck_destructor);
167 :
168 : // Ref the buffer so that we can free it later
169 6524 : GstBuffer* ref = gst_buffer_ref(buffer);
170 : GF_Err err =
171 6524 : gf_filter_pck_set_property(packet, GF_PROP_PCK_UDTA, &PROP_POINTER(ref));
172 6524 : if (G_UNLIKELY(err != GF_OK)) {
173 0 : GST_ELEMENT_ERROR(element,
174 : STREAM,
175 : FAILED,
176 : (NULL),
177 : ("Failed to save the buffer ref to the packet"));
178 0 : gst_buffer_unref(ref);
179 0 : gf_filter_pck_unref(packet);
180 0 : return NULL;
181 : }
182 :
183 : // Get the fps from the PID
184 6524 : GF_Fraction fps = { 30, 1 };
185 6524 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
186 6524 : if (p)
187 4637 : fps = p->value.frac;
188 :
189 : // Get the timescale from the PID
190 6524 : guint64 timescale = GST_SECOND;
191 6524 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
192 6524 : if (p)
193 6524 : timescale = p->value.uint;
194 :
195 : // Set the DTS to DTS or PTS, whichever is valid
196 6524 : if (GST_BUFFER_DTS_IS_VALID(buffer) || GST_BUFFER_PTS_IS_VALID(buffer)) {
197 : guint64 dts =
198 6524 : gpac_pck_get_stream_time(GST_BUFFER_DTS_OR_PTS(buffer), priv, TRUE);
199 6524 : dts = gpac_time_rescale_with_fps(dts, fps, timescale);
200 6524 : gf_filter_pck_set_dts(packet, dts);
201 : }
202 :
203 : // Set the CTS to PTS if it's valid
204 6524 : if (GST_BUFFER_PTS_IS_VALID(buffer)) {
205 6524 : guint64 cts = gpac_pck_get_stream_time(GST_BUFFER_PTS(buffer), priv, FALSE);
206 6524 : cts = gpac_time_rescale_with_fps(cts, fps, timescale);
207 6524 : gf_filter_pck_set_cts(packet, cts);
208 : }
209 :
210 : // Set the duration
211 6524 : if (GST_BUFFER_DURATION_IS_VALID(buffer)) {
212 6524 : guint64 duration = GST_BUFFER_DURATION(buffer);
213 6524 : duration = gpac_time_rescale_with_fps(duration, fps, timescale);
214 6524 : gf_filter_pck_set_duration(packet, duration);
215 : }
216 :
217 : // Set packet framing
218 6524 : gf_filter_pck_set_framing(packet, GF_TRUE, GF_TRUE);
219 :
220 : // Set the default SAP type
221 6524 : gf_filter_pck_set_sap(packet, GF_FILTER_SAP_1);
222 :
223 : // Check if this is a video
224 : const GF_PropertyValue* p_typ =
225 6524 : gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
226 6524 : gboolean is_video = p_typ && p_typ->value.uint == GF_STREAM_VISUAL;
227 :
228 : // For video streams, we need further configuration
229 6524 : if (is_video) {
230 4637 : gpac_configure_video(buffer, priv, packet);
231 : }
232 :
233 : // Configure the packet properties
234 6524 : gpac_pck_prop_configure(buffer, priv, packet, pid);
235 :
236 6524 : return packet;
237 : }
|