]> git.sesse.net Git - mlt/blob - src/modules/linsys/consumer_SDIstream.c
Cleanup unused parameters.
[mlt] / src / modules / linsys / consumer_SDIstream.c
1 /*
2  *
3  * MLT SDI Consumer: request video and audio data from MLT and generate an SDI stream
4  * Copyright (C) 2008 Broadcasting Center Europe S.A. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  *
21  *
22  * DESCRIPTION:
23  * This software act as interface between the MLT Frameworkas as
24  * MLT Consumer and the Linear Systems Ltd. SMPTE 259M-C boards.
25  *
26  * Linear Systems can be contacted at http://www.linsys.ca
27  *
28  * ---------------------------------------------------------------
29  *      System : INTeL I686 64Bit
30  *          OS : Linux SuSE Kernel 2.6.27.23-0.1-default
31  *     Compiler: gcc  (c++)
32  * ---------------------------------------------------------------
33  *     Project : MLT SDI Consumer for SD
34  *  Started by : Thomas Kurpick, Dipl.Inf. (FH)
35  * ---------------------------------------------------------------
36  * This program writes an SDI stream to the SDI driver provided
37  * device files. E.g. SDI device file:
38  *   /dev/sditx0         (SD)
39  *   /dev/sditx1         (SD)
40  *   /dev/sditx2         (SD)
41  *   /dev/sditx4         (SD)
42  *
43  * Tested with:
44  *      SDI Master™ PCI
45  *      SDI Master™ PCIe
46  *      SDI Master™ FD PCIe LP
47  *      SDI Master™ Quad/o PCIe LP
48  *
49  */
50
51 /*
52  * consumer_SDIstream.c
53  * Consumer for MLT Framework > 0.2.4 (release 0.2.4 does NOT work, profiles where not implemented)
54  *
55  * Example:
56  *      inigo video.dv -consumer linsys_sdi:/dev/sditx0 buffer=0;
57  *      melt video.dv -consumer linsys_sdi:/dev/sditx0 buffer=0;
58  *
59  */
60
61 #include <framework/mlt_frame.h>
62 #include <framework/mlt_consumer.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <pthread.h>
67 #include <stdint.h>
68 #include <unistd.h>
69
70 #include "sdi_generator.c"
71
72 typedef struct consumer_SDIstream_s *consumer_SDIstream;
73
74 struct consumer_SDIstream_s {
75
76         struct mlt_consumer_s parent; // This is the basic Consumer from which we fetch our data
77         char *path_destination_sdi; // Path for SDI output
78         int16_t audio_buffer[8][MAX_AUDIO_SAMPLES]; // The SDI audio channel pairs for this frame
79 };
80
81 /** Forward references to static functions.
82  */
83
84 static int consumer_start(mlt_consumer this);
85 static int consumer_stop(mlt_consumer this);
86 static int consumer_is_stopped(mlt_consumer this);
87 static void consumer_close(mlt_consumer parent);
88 static void *consumer_thread(void *);
89
90 //*****************************************************************************************************
91 //*****************************************************************************************************
92 //*******************************************SDI Master Consumer***************************************
93 //*****************************************************************************************************
94 //*****************************************************************************************************
95
96
97 /**
98  * This is what will be called by the factory
99  * @param profile: profile name for consumer
100  * @param type: unused
101  * @param *id: unused
102  * @param *arg: pointer to output path
103  **/
104 mlt_consumer consumer_SDIstream_init(mlt_profile profile, mlt_service_type type, const char *id, char *arg) {
105
106         // Create the consumer object
107         consumer_SDIstream this = calloc(sizeof(struct consumer_SDIstream_s), 1);
108
109         // If malloc and consumer init ok
110         if (this != NULL && mlt_consumer_init(&this->parent, this, profile) == 0) {
111                 // Get the parent consumer object
112                 mlt_consumer parent = &this->parent;
113
114                 // We have stuff to clean up, so override the close method
115                 parent->close = consumer_close;
116
117                 // Set output path for SDI, default is "/dev/sditx0"
118                 if (arg == NULL) {
119                         this->path_destination_sdi = strdup("/dev/sditx0");
120                 } else {
121                         this->path_destination_sdi = strdup(arg);
122                 }
123
124                 // Set up start/stop/terminated callbacks
125                 parent->start = consumer_start;
126                 parent->stop = consumer_stop;
127                 parent->is_stopped = consumer_is_stopped;
128
129                 // Hardcode the audio sample rate to 48KHz for SDI
130                 mlt_properties_set_int(MLT_CONSUMER_PROPERTIES(parent), "frequency", 48000);
131
132                 // Return the consumer produced
133                 return parent;
134         }
135
136         // malloc or consumer init failed
137         free(this);
138
139         // Indicate failure
140         return NULL;
141 }
142
143 /**
144  * Start the consumer.
145  **/
146 static int consumer_start(mlt_consumer parent) {
147         // Get the properties
148         mlt_properties properties = mlt_consumer_properties(parent);
149
150         // Get the actual object
151         consumer_SDIstream this = parent->child;
152
153         // Check that we're not already running
154         if (!mlt_properties_get_int(properties, "running")) {
155                 // Allocate threads
156                 pthread_t *consumer_pthread = calloc(1, sizeof(pthread_t));
157
158                 // Assign the thread to properties
159                 mlt_properties_set_data(properties, "consumer_pthread", consumer_pthread, sizeof(pthread_t), free, NULL);
160
161                 // Set the running state
162                 mlt_properties_set_int(properties, "running", 1);
163
164                 // Create the the threads
165                 pthread_create(consumer_pthread, NULL, consumer_thread, this);
166         }
167         return 0;
168 }
169
170 /**
171  * Stop the consumer.
172  **/
173 static int consumer_stop(mlt_consumer parent) {
174
175         // Get the properties
176         mlt_properties properties = mlt_consumer_properties(parent);
177
178         // Check that we're running
179         if (mlt_properties_get_int(properties, "running")) {
180                 // Get the threads
181                 pthread_t *consumer_pthread = mlt_properties_get_data(properties, "consumer_pthread", NULL);
182
183                 // Stop the threads
184                 mlt_properties_set_int(properties, "running", 0);
185
186                 // Wait for termination
187                 pthread_join(*consumer_pthread, NULL);
188         }
189         return 0;
190 }
191
192 /**
193  * Determine if the consumer is stopped.
194  **/
195 static int consumer_is_stopped(mlt_consumer this) {
196         // Get the properties
197         mlt_properties properties = mlt_consumer_properties(this);
198         return !mlt_properties_get_int(properties, "running");
199 }
200
201 /**
202  * Threaded wrapper for pipe.
203  **/
204 static void *consumer_thread(void *arg) {
205         // Identify the arg
206         consumer_SDIstream this = arg;
207
208         // Get the consumer
209         mlt_consumer consumer = &this->parent;
210
211         // Convenience functionality (this is to stop melt/inigo after the end of a playout)
212         int terminate_on_pause = mlt_properties_get_int(MLT_CONSUMER_PROPERTIES(consumer), "terminate_on_pause");
213         int terminated = 0;
214
215         // Define a frame pointer
216         mlt_frame frame;
217
218         if (!sdimaster_init(this->path_destination_sdi, 0)) {
219                 exit(0);
220         }
221
222         // set Datablock number for SDI encoding
223         int my_dbn = 1;
224
225         double fps = mlt_properties_get_double(MLT_CONSUMER_PROPERTIES(consumer), "fps");
226         unsigned int count = 0;
227
228         // Loop until told not to
229         while (!consumer_is_stopped(consumer) && terminated == 0) { //
230
231                 // Get a frame from the service
232                 if ((frame = mlt_consumer_rt_frame(consumer)) != NULL) {
233
234                         // Check for termination
235                         if (terminate_on_pause && frame != NULL) {
236                                 terminated = mlt_properties_get_double(MLT_FRAME_PROPERTIES(frame), "_speed") == 0.0;
237                                 if (terminated == 1) {
238                                         printf("\nEnd of playout reached, terminating\n");
239                                         fflush(stdout);
240                                         consumer_stop(consumer);
241                                 }
242                         }
243
244                         // True if mlt_consumer_rt_frame(...) successful
245                         if (mlt_properties_get_int(mlt_frame_properties(frame), "rendered") == 1) {
246                                 mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer);
247
248                                 // Tell the framework how we want our audio and video
249                                 int width = mlt_properties_get_int(properties, "width");
250                                 int height = mlt_properties_get_int(properties, "height");
251                                 int frequency = 48000;
252                                 int channels = 0;
253                                 int samples = mlt_sample_calculator(fps, frequency, count++);
254                                 mlt_image_format pix_fmt = mlt_image_yuv422;
255                                 mlt_audio_format aformat = mlt_audio_s16;
256                                 uint8_t *video_buffer;
257                                 int16_t *audio_buffer_tmp; // the upstream audio buffer
258
259                                 // Get the video from this frame and save it to our video_buffer
260                                 mlt_frame_get_image(frame, &video_buffer, &pix_fmt, &width, &height, 0);
261
262                                 // Get the audio from this frame and save it to our audio_buffer
263                                 mlt_frame_get_audio(frame, (void**) &audio_buffer_tmp, &aformat, &frequency, &channels, &samples);
264
265 //                              printf("\n channels: %i samples: %i\n", channels, samples);
266
267                                 // Tell the sdi_generator.c to playout our frame
268                                 // 8 audio streams with 2 stereo channels are possible
269                                 if (video_buffer) {
270                                         int c;
271                                         for (c = 0; c < channels/2; c++) {
272                                                 int16_t *src = audio_buffer_tmp + c * 2;
273                                                 int16_t *dest = this->audio_buffer[c];
274                                                 int s = samples + 1;
275                                                 while (--s) {
276                                                         memcpy(dest, src, 2 * sizeof(int16_t));
277                                                         dest += 2;
278                                                         src += channels;
279                                                 }
280                                         }
281                                         my_dbn = sdimaster_playout(video_buffer, this->audio_buffer, channels / 2, my_dbn);
282                                 } else
283                                         printf("SDI-Consumer: Videobuffer was NULL, skipping playout!\n");
284
285                         } else {
286                                 printf("WARNING the requested frame is not yet rendered! This will cause image disturbance!\n");
287                         }
288
289                         if (frame != NULL)
290                                 mlt_frame_close(frame);
291                 }
292         }
293         return NULL;
294 }
295
296 /**
297  * Callback to allow override of the close method.
298  **/
299 static void consumer_close(mlt_consumer parent) {
300
301         // Get the actual object
302         consumer_SDIstream this = parent->child;
303
304         free(this->path_destination_sdi);
305
306         // Now clean up the rest (the close = NULL is a bit nasty but needed for now)
307         parent->close = NULL;
308         mlt_consumer_close(parent);
309
310         // Invoke the close function of the sdi_generator to close opened files used for output
311         sdimaster_close();
312
313         // Finally clean up this
314         free(this);
315 }