• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer split muxer bin
2  * Copyright (C) 2014-2019 Jan Schmidt <jan@centricular.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #ifndef __GST_SPLITMUXSINK_H__
21 #define __GST_SPLITMUXSINK_H__
22 
23 #include <gst/gst.h>
24 #include <gst/pbutils/pbutils.h>
25 #include <gst/base/base.h>
26 
27 G_BEGIN_DECLS
28 #define GST_TYPE_SPLITMUX_SINK               (gst_splitmux_sink_get_type())
29 #define GST_SPLITMUX_SINK(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPLITMUX_SINK,GstSplitMuxSink))
30 #define GST_SPLITMUX_SINK_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPLITMUX_SINK,GstSplitMuxSinkClass))
31 #define GST_IS_SPLITMUX_SINK(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPLITMUX_SINK))
32 #define GST_IS_SPLITMUX_SINK_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPLITMUX_SINK))
33 typedef struct _GstSplitMuxSink GstSplitMuxSink;
34 typedef struct _GstSplitMuxSinkClass GstSplitMuxSinkClass;
35 
36 GType gst_splitmux_sink_get_type (void);
37 
38 typedef enum _SplitMuxInputState
39 {
40   SPLITMUX_INPUT_STATE_STOPPED,
41   SPLITMUX_INPUT_STATE_COLLECTING_GOP_START,    /* Waiting for the next ref ctx keyframe */
42   SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT,     /* Waiting for all streams to collect GOP */
43   SPLITMUX_INPUT_STATE_FINISHING_UP             /* Got EOS from reference ctx, send everything */
44 } SplitMuxInputState;
45 
46 typedef enum _SplitMuxOutputState
47 {
48   SPLITMUX_OUTPUT_STATE_STOPPED,
49   SPLITMUX_OUTPUT_STATE_AWAITING_COMMAND,       /* Waiting first command packet from input */
50   SPLITMUX_OUTPUT_STATE_OUTPUT_GOP,     /* Outputting a collected GOP */
51   SPLITMUX_OUTPUT_STATE_ENDING_FILE,    /* Finishing the current fragment */
52   SPLITMUX_OUTPUT_STATE_ENDING_STREAM,  /* Finishing up the entire stream due to input EOS */
53   SPLITMUX_OUTPUT_STATE_START_NEXT_FILE /* Restarting after ENDING_FILE */
54 } SplitMuxOutputState;
55 
56 typedef struct _SplitMuxOutputCommand
57 {
58   gboolean start_new_fragment;  /* Whether to start a new fragment before advancing output ts */
59   GstClockTimeDiff max_output_ts;       /* Set the limit to stop GOP output */
60 } SplitMuxOutputCommand;
61 
62 typedef struct _MqStreamBuf
63 {
64   gboolean keyframe;
65   GstClockTimeDiff run_ts;
66   guint64 buf_size;
67   GstClockTime duration;
68 } MqStreamBuf;
69 
70 typedef struct {
71   /* For the very first GOP if it was created from a GAP event */
72   gboolean from_gap;
73 
74   /* Minimum start time (PTS or DTS) of the GOP */
75   GstClockTimeDiff start_time;
76   /* Start time (PTS) of the GOP */
77   GstClockTimeDiff start_time_pts;
78   /* Minimum start timecode of the GOP */
79   GstVideoTimeCode *start_tc;
80 
81   /* Number of bytes we've collected into the GOP */
82   guint64 total_bytes;
83   /* Number of bytes from the reference context
84    * that we've collected into the GOP */
85   guint64 reference_bytes;
86 
87   gboolean sent_fku;
88 } InputGop;
89 
90 typedef struct _MqStreamCtx
91 {
92   GstSplitMuxSink *splitmux;
93 
94   guint q_overrun_id;
95   guint sink_pad_block_id;
96   guint src_pad_block_id;
97   gulong fragment_block_id;
98 
99   gboolean is_reference;
100 
101   gboolean flushing;
102   gboolean in_eos;
103   gboolean out_eos;
104   gboolean out_eos_async_done;
105   gboolean need_unblock;
106   gboolean caps_change;
107   gboolean is_releasing;
108 
109   GstSegment in_segment;
110   GstSegment out_segment;
111 
112   GstClockTimeDiff in_running_time;
113   GstClockTimeDiff out_running_time;
114 
115   GstElement *q;
116   GQueue queued_bufs;
117 
118   GstPad *sinkpad;
119   GstPad *srcpad;
120 
121   GstBuffer *cur_out_buffer;
122   GstEvent *pending_gap;
123 } MqStreamCtx;
124 
125 struct _GstSplitMuxSink
126 {
127   GstBin parent;
128 
129   GMutex state_lock;
130   gboolean shutdown;
131 
132   GMutex lock;
133 
134   GCond input_cond;
135   GCond output_cond;
136 
137   gdouble mux_overhead;
138 
139   GstClockTime threshold_time;
140   guint64 threshold_bytes;
141   guint max_files;
142   gboolean send_keyframe_requests;
143   gchar *threshold_timecode_str;
144   /* created from threshold_timecode_str */
145   GstVideoTimeCodeInterval *tc_interval;
146   GstClockTime alignment_threshold;
147   /* expected running time of next force keyframe unit event */
148   GstClockTime next_fku_time;
149 
150   gboolean reset_muxer;
151 
152   GstElement *muxer;
153   GstElement *sink;
154 
155   GstElement *provided_muxer;
156 
157   GstElement *provided_sink;
158   GstElement *active_sink;
159 
160   gboolean ready_for_output;
161 
162   gchar *location;
163   guint fragment_id;
164   guint start_index;
165   GList *contexts;
166 
167   SplitMuxInputState input_state;
168   GstClockTimeDiff max_in_running_time;
169   GstClockTimeDiff max_in_running_time_dts;
170 
171   /* Number of bytes sent to the
172    * current fragment */
173   guint64 fragment_total_bytes;
174   /* Number of bytes for the reference
175    * stream in this fragment */
176   guint64 fragment_reference_bytes;
177 
178   /* Minimum start time (PTS or DTS) of the current fragment */
179   GstClockTimeDiff fragment_start_time;
180   /* Start time (PTS) of the current fragment */
181   GstClockTimeDiff fragment_start_time_pts;
182   /* Minimum start timecode of the current fragment */
183   GstVideoTimeCode *fragment_start_tc;
184 
185   /* Oldest GOP at head, newest GOP at tail */
186   GQueue pending_input_gops;
187 
188   /* expected running time of next fragment in timecode mode */
189   GstClockTime next_fragment_start_tc_time;
190 
191   GQueue out_cmd_q;             /* Queue of commands for output thread */
192 
193   SplitMuxOutputState output_state;
194   GstClockTimeDiff max_out_running_time;
195 
196   guint64 muxed_out_bytes;
197 
198   MqStreamCtx *reference_ctx;
199   /* Count of queued keyframes in the reference ctx */
200   guint queued_keyframes;
201 
202   gboolean switching_fragment;
203 
204   gboolean have_video;
205 
206   gboolean need_async_start;
207   gboolean async_pending;
208 
209   gboolean use_robust_muxing;
210   gboolean muxer_has_reserved_props;
211 
212   gboolean split_requested;
213   gboolean do_split_next_gop;
214   GstQueueArray *times_to_split;
215 
216   /* Async finalize options */
217   gboolean async_finalize;
218   gchar *muxer_factory;
219   gchar *muxer_preset;
220   GstStructure *muxer_properties;
221   gchar *sink_factory;
222   gchar *sink_preset;
223   GstStructure *sink_properties;
224 
225   GstStructure *muxerpad_map;
226 };
227 
228 struct _GstSplitMuxSinkClass
229 {
230   GstBinClass parent_class;
231 
232   /* actions */
233   void     (*split_now)   (GstSplitMuxSink * splitmux);
234   void     (*split_after) (GstSplitMuxSink * splitmux);
235   void     (*split_at_running_time)   (GstSplitMuxSink * splitmux, GstClockTime split_time);
236 };
237 
238 GST_ELEMENT_REGISTER_DECLARE (splitmuxsink);
239 
240 G_END_DECLS
241 #endif /* __GST_SPLITMUXSINK_H__ */
242