1 /* GStreamer split muxer bin
2  * Copyright (C) 2014 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 gboolean register_splitmuxsink (GstPlugin * plugin);
38 
39 typedef enum _SplitMuxInputState
40 {
41   SPLITMUX_INPUT_STATE_STOPPED,
42   SPLITMUX_INPUT_STATE_COLLECTING_GOP_START,    /* Waiting for the next ref ctx keyframe */
43   SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT,     /* Waiting for all streams to collect GOP */
44   SPLITMUX_INPUT_STATE_FINISHING_UP             /* Got EOS from reference ctx, send everything */
45 } SplitMuxInputState;
46 
47 typedef enum _SplitMuxOutputState
48 {
49   SPLITMUX_OUTPUT_STATE_STOPPED,
50   SPLITMUX_OUTPUT_STATE_AWAITING_COMMAND,       /* Waiting first command packet from input */
51   SPLITMUX_OUTPUT_STATE_OUTPUT_GOP,     /* Outputting a collected GOP */
52   SPLITMUX_OUTPUT_STATE_ENDING_FILE,    /* Finishing the current fragment */
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 _MqStreamCtx
71 {
72   GstSplitMuxSink *splitmux;
73 
74   guint q_overrun_id;
75   guint sink_pad_block_id;
76   guint src_pad_block_id;
77   gulong fragment_block_id;
78 
79   gboolean is_reference;
80 
81   gboolean flushing;
82   gboolean in_eos;
83   gboolean out_eos;
84   gboolean out_eos_async_done;
85   gboolean need_unblock;
86   gboolean caps_change;
87 
88   GstSegment in_segment;
89   GstSegment out_segment;
90 
91   GstClockTimeDiff in_running_time;
92   GstClockTimeDiff out_running_time;
93 
94   GstBuffer *prev_in_keyframe; /* store keyframe for each GOP */
95 
96   GstElement *q;
97   GQueue queued_bufs;
98 
99   GstPad *sinkpad;
100   GstPad *srcpad;
101 
102   GstBuffer *cur_out_buffer;
103   GstEvent *pending_gap;
104 } MqStreamCtx;
105 
106 struct _GstSplitMuxSink
107 {
108   GstBin parent;
109 
110   GMutex lock;
111   GCond input_cond;
112   GCond output_cond;
113 
114   gdouble mux_overhead;
115 
116   GstClockTime threshold_time;
117   guint64 threshold_bytes;
118   guint max_files;
119   gboolean send_keyframe_requests;
120   gchar *threshold_timecode_str;
121   GstClockTime next_max_tc_time;
122   GstClockTime alignment_threshold;
123 
124   gboolean reset_muxer;
125 
126   GstElement *muxer;
127   GstElement *sink;
128 
129   GstElement *provided_muxer;
130 
131   GstElement *provided_sink;
132   GstElement *active_sink;
133 
134   gboolean ready_for_output;
135 
136   gchar *location;
137   guint fragment_id;
138 
139   GList *contexts;
140 
141   SplitMuxInputState input_state;
142   GstClockTimeDiff max_in_running_time;
143   /* Number of bytes sent to the
144    * current fragment */
145   guint64 fragment_total_bytes;
146   /* Number of bytes we've collected into
147    * the GOP that's being collected */
148   guint64 gop_total_bytes;
149   /* Start time of the current fragment */
150   GstClockTimeDiff fragment_start_time;
151   /* Start time of the current GOP */
152   GstClockTimeDiff gop_start_time;
153 
154   GQueue out_cmd_q;             /* Queue of commands for output thread */
155 
156   SplitMuxOutputState output_state;
157   GstClockTimeDiff max_out_running_time;
158 
159   guint64 muxed_out_bytes;
160 
161   MqStreamCtx *reference_ctx;
162   /* Count of queued keyframes in the reference ctx */
163   guint queued_keyframes;
164 
165   gboolean switching_fragment;
166 
167   gboolean have_video;
168 
169   gboolean need_async_start;
170   gboolean async_pending;
171 
172   gboolean use_robust_muxing;
173   gboolean muxer_has_reserved_props;
174 
175   gboolean split_requested;
176   gboolean do_split_next_gop;
177   GstQueueArray *times_to_split;
178 
179   /* Async finalize options */
180   gboolean async_finalize;
181   gchar *muxer_factory;
182   GstStructure *muxer_properties;
183   gchar *sink_factory;
184   GstStructure *sink_properties;
185 };
186 
187 struct _GstSplitMuxSinkClass
188 {
189   GstBinClass parent_class;
190 
191   /* actions */
192   void     (*split_now)   (GstSplitMuxSink * splitmux);
193   void     (*split_after) (GstSplitMuxSink * splitmux);
194   void     (*split_at_running_time)   (GstSplitMuxSink * splitmux, GstClockTime split_time);
195 };
196 
197 G_END_DECLS
198 #endif /* __GST_SPLITMUXSINK_H__ */
199