4 * request video and audio data from MLT and generate an SDI stream
6 * Copyright (C) Broadcasting Center Europe S.A. http://www.bce.lu
7 * an RTL Group Company http://www.rtlgroup.com
10 * E-mail: support_plasec@bce.lu
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29 * This software act as interface between the MLT Frameworkas as
30 * MLT Consumer and the Linear Systems Ltd. SMPTE 292M and SMPTE 259M-C boards.
32 * Linear Systems can be contacted at http://www.linsys.ca
34 **********************************************************************************
35 * System : INTeL I686 64Bit
36 * OS : Linux SuSE Kernel 2.6.27.39-0.2-default
37 * Compiler: gcc 4.3.2 (c++)
38 **********************************************************************************
39 * Project : MLT SDI Consumer for SD and HD
40 * Started by : Thomas Kurpick, Dipl.Inf. (FH)
41 **********************************************************************************
42 * Supported and tested boards for SD-SDI or HD-SDI Output:
43 * PCI SDI Master™ (model 107)
44 * PCIe SDI Master™ (model 159)
45 * PCIe LP SDI Master™ FD (model 145)
46 * PCIe LP SDI Master™ Quad/o (model 180)
47 * PCIe LP HD-SDI Master™ O (model 193)
49 * Note: PCIe LP HD-SDI Master™ O (model 193) is an VidPort model and supports an
50 * seperate video and audio interface. Device file:
51 * /dev/sdivideotx[] for active video data
52 * /dev/sdiaudiotx[] for pcm audio data
54 * This mlt consumer use the following device files:
55 * /dev/sditx[] (SD-PAL) up to 8 x AES (8 x stereo / 16 audio channels)
56 * /dev/sdivideotx[] (HD)
57 * /dev/sdiaudiotx[] (HD) up to 4 x AES (4 x stereo / 8 audio channels)
60 **********************************************************************************
62 * Thomas Kurpick 08.Jan.2010
65 **********************************************************************************
67 * Consumer properties:
71 * Only to monitor the SDI output a beta version of jpeg-writer is implemented.
72 * 'jpeg_files' a number for output interval
73 * 'save_jpegs' path for image
77 * SDI boards with full frame stream (with blanking):
78 * melt video.dv -consumer sdi:/dev/sditx0 buffer=0;
79 * melt video.dv -consumer sdi:/dev/sditx0 buffer=0 blanking=true;
80 * melt video.dv -consumer sdi dev_video=/dev/sditx0 buffer=0 blanking=true;
81 * melt video.dv audio_index=all -consumer sdi dev_video=/dev/sditx0 buffer=0 blanking=true;
83 * SDI boards without full frame stream (without blanking):
84 * melt -profile atsc_1080i_50 video.mpeg audio_index=1 -consumer sdi dev_video=/dev/sdivideotx0 dev_sdiaudio=/dev/sdiaudiotx0 blanking=false
85 * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_sdiaudio=/dev/sdiaudiotx0 blanking=false
86 * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_sdiaudio=/dev/sdiaudiotx0 blanking=false jpeg_files=25 save_jpegs=channel_04.jpg
89 * SDI output formats and MLT profiles:
90 * #####################################################################################################################################################
91 * ########## SMPTE 274M 1920 x 1080 Image Sample Structure ############################################################################################
92 * #####################################################################################################################################################
93 * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model)
94 * 4 1920 x 1080/60/I interlaced 30 HZ 4 x AES (8 channels) atsc_1080i_60 193
95 * 5 1920 x 1080/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080i_5994 193
96 * 6 1920 x 1080/50/I interlaced 25 HZ 4 x AES (8 channels) atsc_1080i_50 193
97 * 7 1920 x 1080/30/P progressive 30 HZ 4 x AES (8 channels) atsc_1080p_30 193
98 * 8 1920 x 1080/29.97/P progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080p_2997 193
99 * 9 1920 x 1080/25/P progressive 25 HZ 4 x AES (8 channels) atsc_1080p_25 193
100 * 10 1920 x 1080/24/P progressive 24 HZ 4 x AES (8 channels) atsc_1080p_24 193
101 * 11 1920 x 1080/23.98/P progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_1080p_2398 193
103 * #####################################################################################################################################################
104 * ########## SMPTE 296M 1280 × 720 Progressive Image Sample Structure #################################################################################
105 * #####################################################################################################################################################
106 * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model)
107 * 1 1280 × 720/60 progressive 60 HZ 4 x AES (8 channels) atsc_720p_60 193
108 * 2 1280 × 720/59.94 progressive 60000/1001 ~ 59.97 HZ 4 x AES (8 channels) atsc_720p_5994 193
109 * 3 1280 × 720/50 progressive 50 HZ 4 x AES (8 channels) atsc_720p_50 193
110 * 4 1280 × 720/30 progressive 30 HZ 4 x AES (8 channels) atsc_720p_30 193
111 * 5 1280 × 720/29.97 progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_720p_2997 193
112 * 6 1280 × 720/25 progressive 25 HZ 4 x AES (8 channels) atsc_720p_25 193
113 * 7 1280 × 720/24 progressive 24 HZ 4 x AES (8 channels) atsc_720p_24 193
114 * 8 1280 × 720/23.98 progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_720p_2398 193
116 * #####################################################################################################################################################
117 * ########## SMPTE 125M 486i 29.97Hz & BT.656 576i 25Hz ###############################################################################################
118 * #####################################################################################################################################################
119 * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model)
120 * SD PAL 720 × 576/50/I interlaced 25 HZ 8 x AES (16 channels) dv_pal 180,145,159,107
121 * SD PAL 720 × 576/50/I interlaced 25 HZ 4 x AES (8 channels) dv_pal 193
122 * SD NTSC 720 × 480/59.94/I interlaced 30000/1001 ~ 29.97 HZ 8 x AES (16 channels) sdi_486i_5994 TODO:180,145,159,107
123 * SD NTSC 720 × 480/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) sdi_486i_5994 193
127 #include "sdi_generator.h"
129 /*!/brief Initialization of the file handlers for the Playout
130 * @param *device_video: file or SDITX device or SDIVIDEOTX device
131 * @param *device_audio: file or SDIAUDIOTX device
132 * @param blanking: true or false (if false the consumer write only active video data without any VANH or HANC)
134 static int sdi_init(char *device_video, char *device_audio, uint8_t blanking, mlt_profile myProfile) {
137 device_file_video = device_video;
138 device_file_audio = device_audio;
140 // set flag for using of blanking with anilary data
141 info.blanking = blanking;
143 // set pack methode for SDI word conversion
149 if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1 && myProfile->progressive
151 info.fmt = &FMT_1080i60;
152 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001
153 && myProfile->progressive == 0) {
154 info.fmt = &FMT_1080i5994;
155 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
156 && myProfile->progressive == 0) {
157 info.fmt = &FMT_1080i50;
158 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1
159 && myProfile->progressive == 1) {
160 info.fmt = &FMT_1080p30;
161 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001
162 && myProfile->progressive == 1) {
163 info.fmt = &FMT_1080p2997;
164 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
165 && myProfile->progressive == 1) {
166 info.fmt = &FMT_1080p25;
167 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 24 && myProfile->frame_rate_den == 1
168 && myProfile->progressive == 1) {
169 info.fmt = &FMT_1080p24;
170 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 24000 && myProfile->frame_rate_den == 1001
171 && myProfile->progressive == 1) {
172 info.fmt = &FMT_1080p2398;
173 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 60 && myProfile->frame_rate_den == 1
174 && myProfile->progressive == 1) {
175 info.fmt = &FMT_720p60;
176 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 60000 && myProfile->frame_rate_den == 1001
177 && myProfile->progressive == 1) {
178 info.fmt = &FMT_720p5994;
179 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 50 && myProfile->frame_rate_den == 1
180 && myProfile->progressive == 1) {
181 info.fmt = &FMT_720p50;
182 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1
183 && myProfile->progressive == 1) {
184 info.fmt = &FMT_720p30;
185 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001
186 && myProfile->progressive == 1) {
187 info.fmt = &FMT_720p2997;
188 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
189 && myProfile->progressive == 1) {
190 info.fmt = &FMT_720p25;
191 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 24 && myProfile->frame_rate_den == 1
192 && myProfile->progressive == 1) {
193 info.fmt = &FMT_720p24;
194 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 24000 && myProfile->frame_rate_den == 1001
195 && myProfile->progressive == 1) {
196 info.fmt = &FMT_720p2398;
197 } else if (myProfile->width == 720 && myProfile->height == 576 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
198 && myProfile->progressive == 0) {
199 info.fmt = &FMT_576i50;
200 } else if (myProfile->width == 720 && myProfile->height == 480 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001
201 && myProfile->progressive == 0) {
202 info.fmt = &FMT_480i5994;
204 printf("Consumer gets unknown format: %s", myProfile->description);
205 info.fmt = &FMT_576i50;
208 printf("Consumer use format: %s\nProfile: %i %i %i %i %i\n", myProfile->description, myProfile->width, myProfile->height, myProfile->frame_rate_num,
209 myProfile->frame_rate_den, myProfile->progressive);
211 // Check if the format support own blanking (note: model 193 support currently only active video at the video device file)
212 if (info.blanking && info.fmt != &FMT_576i50) {
213 printf("SDI consumer doesn't support blanking(HANC) for this configurred SD board and SDI format. Try arguemnt: blanking=false\n");
217 if (device_file_video != NULL) {
218 // open file handler for SDI(video) output
219 if ((fh_sdi_video = open(device_file_video, O_WRONLY)) == -1) {
221 printf("\ncould not open video output destination: %s\n", device_file_video);
223 printf("SDI consumer use video device file: %s\n", device_file_video);
226 // Check if seperat device file for audio must use
227 if (device_file_audio != NULL) {
228 // open file handler for audio output
229 if ((fh_sdi_audio = open(device_file_audio, O_WRONLY | O_CREAT, 0777)) == -1) {
231 printf("\ncould not open audio output destination: %s\n", device_file_audio);
234 printf("SDI consumer use audio device file: %s\n", device_file_audio);
237 // if we write our own HANC we need an AES channel status bit array
241 // http://www.sencore.com/newsletter/Nov05/DigAudioChannelStatusBits.htm
243 // http://www.sencore.com/uploads/files/DigAudioChannelStatusBits.pdf
245 // create empty AESChannelStatusBitArray
247 for (i = 0; i < sizeof(AESChannelStatusBitArray) / sizeof(AESChannelStatusBitArray[0]); i++)
248 AESChannelStatusBitArray[i] = 0;
251 * Professionel Format - Channel Status Bits
254 AESChannelStatusBitArray[0] = 1; // professional format
256 AESChannelStatusBitArray[1] = 0; // PCM Format
258 AESChannelStatusBitArray[2] = 1; // Emphasis: [100] No Emphasis
259 AESChannelStatusBitArray[3] = 0; // ^
260 AESChannelStatusBitArray[4] = 0; // ^
262 AESChannelStatusBitArray[5] = 0; // locked
264 AESChannelStatusBitArray[6] = 0; // sample frequncy Fs: [01]48kHz, [10]44kHz, [11]32kHz
265 AESChannelStatusBitArray[7] = 1; // ^
267 AESChannelStatusBitArray[8] = 0; // channel mode: [0000] not indicated, [0001]2channels, [0010]1channel mono, ...
268 AESChannelStatusBitArray[9] = 0; // ^
269 AESChannelStatusBitArray[10] = 0; // ^
270 AESChannelStatusBitArray[11] = 1; // ^
272 AESChannelStatusBitArray[19] = 0; // Encoded sample word length [100]20bits,
273 AESChannelStatusBitArray[20] = 0; //
274 AESChannelStatusBitArray[21] = 0; //
276 AESChannelStatusBitArray[24] = 0; //
277 AESChannelStatusBitArray[25] = 0; //
278 AESChannelStatusBitArray[26] = 0; //
279 AESChannelStatusBitArray[27] = 0; //
280 AESChannelStatusBitArray[28] = 0; //
281 AESChannelStatusBitArray[29] = 0; //
282 AESChannelStatusBitArray[30] = 0; //
283 AESChannelStatusBitArray[31] = 0; // Multi Channel Mode
284 ////// Byte 4-21 //////
285 //AESChannelStatusBitArray[32-179]= 0;
286 ////// Byte 22 //////
287 AESChannelStatusBitArray[180] = 0; // Reliability Flags
288 AESChannelStatusBitArray[181] = 1; // ^
289 AESChannelStatusBitArray[182] = 1; // ^
290 AESChannelStatusBitArray[183] = 1; // ^
291 ////// Byte 23 //////
292 AESChannelStatusBitArray[184] = 0; // Cyclic Redundancy Check
293 AESChannelStatusBitArray[185] = 1; // ^
294 AESChannelStatusBitArray[186] = 0; // ^
295 AESChannelStatusBitArray[187] = 0; // ^
296 AESChannelStatusBitArray[188] = 1; // ^
297 AESChannelStatusBitArray[189] = 0; // ^
298 AESChannelStatusBitArray[190] = 1; // ^
299 AESChannelStatusBitArray[191] = 1; // ^
302 // set buffer for one line of active video samples
303 line_buffer = (uint16_t*) calloc(info.fmt->samples_per_line, sizeof(uint16_t));
305 // calculate and set buffer for the complete SDI frame
306 if (info.fmt != &FMT_576i50 && info.fmt != &FMT_480i5994) {
308 if (pack == pack_v210) {
309 samples = (info.fmt->samples_per_line / 96 * 48) + ((info.fmt->samples_per_line % 96) ? 48 : 0);
310 sdi_frame_size = samples * info.fmt->lines_per_frame * 8 / 3;
312 sdi_frame_size = info.fmt->samples_per_line * info.fmt->lines_per_frame;
315 if (pack == pack_v210) {
316 samples = (info.fmt->active_samples_per_line / 96 * 48) + ((info.fmt->active_samples_per_line % 96) ? 48 : 0);
317 sdi_frame_size = samples * info.fmt->active_lines_per_frame * 8 / 3;
319 sdi_frame_size = info.fmt->active_samples_per_line * info.fmt->active_lines_per_frame;
324 if (pack == pack_v210) {
325 sdi_frame_size = info.fmt->samples_per_line * 4 / 3 * info.fmt->lines_per_frame;
326 } else if (pack == pack8) {
327 sdi_frame_size = info.fmt->samples_per_line * info.fmt->lines_per_frame;
329 sdi_frame_size = info.fmt->samples_per_line * 10 / 8 * info.fmt->lines_per_frame;
332 if (pack == pack_v210) {
333 sdi_frame_size = info.fmt->active_samples_per_line * 4 / 3 * info.fmt->active_lines_per_frame;
334 } else if (pack == pack8) {
335 sdi_frame_size = info.fmt->active_samples_per_line * info.fmt->active_lines_per_frame;
337 sdi_frame_size = info.fmt->active_samples_per_line * 10 / 8 * info.fmt->active_lines_per_frame;
342 // hack/overwrite because we use default the pack_v210() not as befor the pack10()
343 //(*10/8 because we store (TOTAL_SAMPLES*TOTAL_LINES) words with 10 bit in this 8 bit array) )
344 if (info.fmt == &FMT_576i50 && info.blanking) {
345 sdi_frame_size = info.fmt->samples_per_line * 10 / 8 * info.fmt->lines_per_frame;
348 printf("SDI frame size:%li\n", sdi_frame_size);
350 // set buffer for the complete SDI frame
351 data = (uint8_t*) calloc(sdi_frame_size, sizeof(uint8_t));
357 * Writes video and audio to specified files in SDI format
358 * @param *vBuffer: Pointer to a video Buffer
360 * @param *audio_format: mlt audio_format
361 * @param audio_streams: number of audio streams which have content in aBuffer (available 0-8)
362 * @return current DBN (data block number of SDI frame)
364 static int sdi_playout(uint8_t *vBuffer, int16_t aBuffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], const struct audio_format * audio_format, int audio_streams,
367 // Pointer to the start of data. This is used to fill data line by line
370 //*******************************************************************************************
371 //**************** Build the SDI frame line by line ****************************************
372 //*******************************************************************************************
375 * if SDI FMT_576i50 for card ASSY 145 or ASSY 159, with access to whole SDI frame buffer
376 * and device_file_audio must be NULL
377 * than we write own audio data,
379 * than HD for card ASSY 193
381 //if (info.fmt == &FMT_576i50 && device_file_audio == NULL && !strcmp(device_file_video, "/dev/sdivideotx0")) {
382 if (info.fmt == &FMT_576i50 && info.blanking) {
384 //counter for the lines
386 int16_t AudioGroupCounter = 0;
388 /*#####################################################*/
389 /*######## FIELD 1 #######################*/
390 /*#####################################################*/
392 info.xyz = &FIELD_1_VERT_BLANKING;
394 // line 1-22 VERTICAL_BLANKING:23 lines SAV 0x2ac EAV 0x2d8
395 for (i = 1; i <= 5; i++) {
396 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
397 getNumberOfAudioGroups2Write(i), audio_streams);
398 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
399 p = pack10(p, line_buffer, info.fmt->samples_per_line);
401 for (i = 6; i <= 8; i++) {
402 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
403 getNumberOfAudioGroups2Write(i), audio_streams);
404 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
405 p = pack10(p, line_buffer, info.fmt->samples_per_line);
407 for (i = 9; i <= 22; i++) {
408 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
409 getNumberOfAudioGroups2Write(i), audio_streams);
410 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
411 p = pack10(p, line_buffer, info.fmt->samples_per_line);
413 // line 23-310 ACTIVE: 287 lines SAV 0x200 EAV 0x274
414 info.xyz = &FIELD_1_ACTIVE;
415 int f1counter = 1; // only odd lines
416 for (i = 23; i <= 310; i++) {
417 create_SD_SDI_Line(line_buffer, &info, FIELD_1, ACTIVE_VIDEO, vBuffer, aBuffer, i, f1counter, getDBN(my_DBN++), AudioGroupCounter,
418 getNumberOfAudioGroups2Write(i), audio_streams);
419 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
420 p = pack10(p, line_buffer, info.fmt->samples_per_line);
424 // line 311-312 VERTICAL_BLANKING: 2 lines SAV 0x2ac EAV 0x2d8
425 info.xyz = &FIELD_1_VERT_BLANKING;
426 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
427 getNumberOfAudioGroups2Write(i), audio_streams);
428 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
429 p = pack10(p, line_buffer, info.fmt->samples_per_line);
430 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
431 getNumberOfAudioGroups2Write(i), audio_streams);
432 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
433 p = pack10(p, line_buffer, info.fmt->samples_per_line);
435 /*#####################################################*/
436 /*######## FIELD 2 ########################*/
437 /*#####################################################*/
439 info.xyz = &FIELD_2_VERT_BLANKING;
441 // line 313-336 VERTICAL_BLANKING: 23 lines SAV 0x3b0 EAV 0x3c4
442 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
443 getNumberOfAudioGroups2Write(i), audio_streams);
444 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
445 p = pack10(p, line_buffer, info.fmt->samples_per_line);
447 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
448 getNumberOfAudioGroups2Write(i), audio_streams);
449 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
450 p = pack10(p, line_buffer, info.fmt->samples_per_line);
452 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
453 getNumberOfAudioGroups2Write(i), audio_streams);
454 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
455 p = pack10(p, line_buffer, info.fmt->samples_per_line);
457 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
458 getNumberOfAudioGroups2Write(i), audio_streams);
459 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
460 p = pack10(p, line_buffer, info.fmt->samples_per_line);
462 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
463 getNumberOfAudioGroups2Write(i), audio_streams);
464 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
465 p = pack10(p, line_buffer, info.fmt->samples_per_line);
467 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
468 getNumberOfAudioGroups2Write(i), audio_streams);
469 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
470 p = pack10(p, line_buffer, info.fmt->samples_per_line);
472 // `getAudioGroups2Write()`=0
473 for (i = 319; i <= 321; i++) {
474 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
475 getNumberOfAudioGroups2Write(i), audio_streams);
476 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
477 p = pack10(p, line_buffer, info.fmt->samples_per_line);
479 for (i = 322; i <= 335; i++) {
480 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
481 getNumberOfAudioGroups2Write(i), audio_streams);
482 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
483 p = pack10(p, line_buffer, info.fmt->samples_per_line);
485 // line 336-623 ACTIVE: 288 lines SAV 0x31c EAV 0x368
486 info.xyz = &FIELD_2_ACTIVE;
487 int f2counter = 2; // only even Lines
488 for (i = 336; i <= 623; i++) {
490 create_SD_SDI_Line(line_buffer, &info, FIELD_2, ACTIVE_VIDEO, vBuffer, aBuffer, i, f2counter, getDBN(my_DBN++), AudioGroupCounter,
491 getNumberOfAudioGroups2Write(i), audio_streams);
492 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
493 p = pack10(p, line_buffer, info.fmt->samples_per_line);
496 // line 624-625 VERTICAL_BLANKING: 2 lines SAV 0x3b0 EAV 0x3c4
497 info.xyz = &FIELD_2_VERT_BLANKING;
498 for (i = 624; i <= 625; i++) {
499 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
500 getNumberOfAudioGroups2Write(i), audio_streams);
501 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
502 p = pack10(p, line_buffer, info.fmt->samples_per_line);
505 } else { // use HD board without blanking
507 // start with first even line
508 active_video_line = 1;
510 /* *****************************************
511 * *********** LINE DISTRIBUTION ***********
512 * *****************************************
514 * << decide form of scanning (interlaced || progressive) >>
516 * << decide lines per frame (1125 || 625 || 525) >>
517 * if(1125) 1080x1920 HD
519 * else if(625) 576x720 PAL
521 * else (525) 486x720 NTSC
524 * << decide resolution (1125 || 750) >>
525 * if(1125) 1080x1920 HD
527 * else(750) 720x1280 HD
533 if (info.fmt->interlaced) {
535 /****************************************
537 ****************************************/
539 if (info.fmt->lines_per_frame == 1125) {
542 elements = info.fmt->samples_per_line;
543 info.xyz = &FIELD_1_VERT_BLANKING;
544 for (info.ln = 1; info.ln <= 20; info.ln++) {
545 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
546 p = pack(p, line_buffer, elements);
549 elements = info.fmt->active_samples_per_line;
551 info.xyz = &FIELD_1_ACTIVE;
552 for (info.ln = 21; info.ln <= 560; info.ln++) {
553 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
554 p = pack(p, line_buffer, elements);
555 active_video_line += 2;
558 info.xyz = &FIELD_1_VERT_BLANKING;
559 for (info.ln = 561; info.ln <= 563; info.ln++) {
560 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
561 p = pack(p, line_buffer, elements);
563 info.xyz = &FIELD_2_VERT_BLANKING;
564 for (info.ln = 564; info.ln <= 583; info.ln++) {
565 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
566 p = pack(p, line_buffer, elements);
569 // start with first odd line
570 active_video_line = 2;
572 info.xyz = &FIELD_2_ACTIVE;
573 for (info.ln = 584; info.ln <= 1123; info.ln++) {
574 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
575 p = pack(p, line_buffer, elements);
576 active_video_line += 2;
579 info.xyz = &FIELD_2_VERT_BLANKING;
580 for (info.ln = 1124; info.ln <= 1125; info.ln++) {
581 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
582 p = pack(p, line_buffer, elements);
585 } else if (info.fmt->lines_per_frame == 625) {
587 elements = info.fmt->active_samples_per_line;
589 // start with first even line
590 active_video_line = 1;
593 * Generate an SDI PAL frame
596 info.xyz = &FIELD_1_VERT_BLANKING;
597 for (info.ln = 1; info.ln <= 22; info.ln++) {
598 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
599 p = pack(p, line_buffer, elements);
602 info.xyz = &FIELD_1_ACTIVE;
603 for (info.ln = 23; info.ln <= 310; info.ln++) {
604 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
605 p = pack(p, line_buffer, elements);
606 active_video_line += 2;
609 info.xyz = &FIELD_1_VERT_BLANKING;
610 for (info.ln = 311; info.ln <= 312; info.ln++) {
611 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
612 p = pack(p, line_buffer, elements);
614 info.xyz = &FIELD_2_VERT_BLANKING;
615 for (info.ln = 313; info.ln <= 335; info.ln++) {
616 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
617 p = pack(p, line_buffer, elements);
621 // start with first odd line
622 active_video_line = 2;
624 info.xyz = &FIELD_2_ACTIVE;
625 for (info.ln = 336; info.ln <= 623; info.ln++) {
626 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
627 p = pack(p, line_buffer, elements);
628 active_video_line += 2;
631 info.xyz = &FIELD_2_VERT_BLANKING;
632 for (info.ln = 624; info.ln <= 625; info.ln++) {
633 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
634 p = pack(p, line_buffer, elements);
637 } else if (info.fmt->lines_per_frame == 525) {
640 * Generate an SDI NTSC frame
642 elements = info.fmt->active_samples_per_line;
644 active_video_line = 1;
647 info.xyz = &FIELD_1_VERT_BLANKING;
648 for (info.ln = 1; info.ln <= 15; info.ln++) {
649 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
650 p = pack(p, line_buffer, elements);
652 for (info.ln = 16; info.ln <= 16; info.ln++) {
653 info.xyz = &FIELD_1_ACTIVE;
654 mkline(line_buffer, &info, VERT_BLANKING);
655 p = pack(p, line_buffer, elements);
659 info.xyz = &FIELD_1_ACTIVE;
660 // 3 lines opt. video data
661 for (info.ln = 17; info.ln <= 19; info.ln++) {
662 mkline(line_buffer, &info, BLACK);
663 p = pack(p, line_buffer, elements);
665 for (info.ln = 20; info.ln <= 259; info.ln++) {
666 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
667 p = pack(p, line_buffer, elements);
668 active_video_line += 2;
671 info.xyz = &FIELD_1_VERT_BLANKING;
672 for (info.ln = 260; info.ln <= 261; info.ln++) {
673 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
674 p = pack(p, line_buffer, elements);
676 info.xyz = &FIELD_2_VERT_BLANKING;
677 // 7 lines vertical data
678 for (info.ln = 262; info.ln <= 269; info.ln++) {
679 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
680 p = pack(p, line_buffer, elements);
682 // 9 lines opt. video data ?? // TODO have look to SMPTE
683 for (info.ln = 270; info.ln <= 278; info.ln++) {
684 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
685 p = pack(p, line_buffer, elements);
690 active_video_line = 0;
691 // 3 lines opt. video data
692 info.xyz = &FIELD_2_ACTIVE;
693 for (info.ln = 279; info.ln <= 281; info.ln++) {
694 mkline(line_buffer, &info, BLACK);
695 p = pack(p, line_buffer, elements);
697 for (info.ln = 282; info.ln <= 521; info.ln++) {
698 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
699 p = pack(p, line_buffer, elements);
700 active_video_line += 2;
703 info.xyz = &FIELD_2_VERT_BLANKING;
704 for (info.ln = 522; info.ln <= 525; info.ln++) {
705 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
706 p = pack(p, line_buffer, elements);
712 /****************************************
714 ****************************************/
716 // start with first line numerber
717 active_video_line = 0;
719 if (info.fmt->lines_per_frame == 1125) {
721 elements = info.fmt->samples_per_line;
722 info.xyz = &FIELD_1_VERT_BLANKING;
723 for (info.ln = 1; info.ln <= 41; info.ln++) {
724 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
725 p = pack(p, line_buffer, elements);
728 elements = info.fmt->active_samples_per_line;
730 info.xyz = &FIELD_1_ACTIVE;
731 for (info.ln = 42; info.ln <= 1121; info.ln++) {
732 create_HD_SDI_Line(line_buffer, &info, active_video_line++, ACTIVE_VIDEO, vBuffer);
733 p = pack(p, line_buffer, elements);
736 info.xyz = &FIELD_1_VERT_BLANKING;
737 for (info.ln = 1122; info.ln <= 1125; info.ln++) {
738 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
739 p = pack(p, line_buffer, elements);
744 elements = info.fmt->samples_per_line;
745 info.xyz = &FIELD_1_VERT_BLANKING;
746 for (info.ln = 1; info.ln <= 25; info.ln++) {
747 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
748 p = pack(p, line_buffer, elements);
751 elements = info.fmt->active_samples_per_line;
753 info.xyz = &FIELD_1_ACTIVE;
754 for (info.ln = 26; info.ln <= 745; info.ln++) {
755 create_HD_SDI_Line(line_buffer, &info, active_video_line++, ACTIVE_VIDEO, vBuffer);
756 p = pack(p, line_buffer, elements);
759 info.xyz = &FIELD_1_VERT_BLANKING;
760 for (info.ln = 746; info.ln <= 750; info.ln++) {
761 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
762 p = pack(p, line_buffer, elements);
769 // sum of bytes that have already been written to file
771 // store actual written bytes per 'write()
772 int written_bytes = 0;
775 * WRITE BUFFER TO FILEHANDLE
777 // Write the complete frame to output
778 // The "while" is necessary because the sdi device file does not take the complete frame at once
780 while (bytes < sdi_frame_size) {
782 if ((written_bytes = write(fh_sdi_video, data + bytes, sdi_frame_size - bytes)) < 0) {
783 fprintf(stderr, "\nunable to write SDI video.\n");
786 bytes += written_bytes;
788 // Check for events of the SDI board
790 if (ioctl(fh_sdi_video, SDI_IOC_TXGETEVENTS, &val) < 0) {
791 // Maybe this is not an SDI device...
792 fprintf(stderr, "SDI VIDEO output:");
793 perror("unable to get the transmitter event flags");
795 if (val & SDI_EVENT_TX_BUFFER) {
796 printf("SDI VIDEO driver transmit buffer queue underrun "
799 if (val & SDI_EVENT_TX_FIFO) {
800 printf("SDI VIDEO onboard transmit FIFO underrun detected.\n");
803 if (val & SDI_EVENT_TX_DATA) {
804 printf("SDI VIDEO transmit data change detected.\n");
810 // if available write audio data
813 // count writen bytes
816 // set number of samples and cut by 1600 if NTSC (handle problem of real time encoding of NTSC frequencies)
817 //size_t samples_total_per_track = audio_format->samples == 1601 || audio_format->samples == 1602 ? 1600 : audio_format->samples; // TODO buffer underrun by NTSC frequencs because of 3/2 pull down
818 size_t samples_total_per_track = audio_format->samples;
819 uint16_t sample_number = 0;
820 size_t channels_per_track_total = 2;
821 uint8_t stream_number = 0;
823 //printf("samples_total_per_track:%li\n", samples_total_per_track);
825 // to write blockwise 2 samples of one track we must claculate the number of bytes we want to write per write-session
826 // 2samples = 2x16Bit = 32Bit = 4Byte
827 // 2samples = 2x32Bit = 64Bit = 8Byte
828 // set total bytes per session
829 size_t bytes_total = 0;
830 bytes_total = audio_format->aformat == mlt_audio_s16 ? channels_per_track_total * sizeof(int16_t) : bytes_total;
831 bytes_total = audio_format->aformat == mlt_audio_s32 ? channels_per_track_total * sizeof(int32_t) : bytes_total; // TODO sdi board must be pre-configured for 32bit samples!!!!
833 // write all samples of all streams interleaved
835 * aBuffer[track0]+sample1
836 * aBuffer[track0]+sample2
837 * aBuffer[track1]+sample1
838 * aBuffer[track1]+sample2
839 * aBuffer[track.]+sample1
840 * aBuffer[track.]+sample2
842 * aBuffer[track0]+sample3
843 * aBuffer[track0]+sample4
844 * aBuffer[track1]+sample3
845 * aBuffer[track1]+sample4
846 * aBuffer[track.]+sample3
847 * aBuffer[track.]+sample4
849 * aBuffer[track0]+sample5
850 * aBuffer[track0]+sample6
851 * aBuffer[track1]+sample5
852 * aBuffer[track1]+sample6
853 * aBuffer[track.]+sample5
854 * aBuffer[track.]+sample6
856 int sum_written_bytes = 0;
857 int sum_written_bytes_a = 0;
858 int sum_written_bytes_b = 0;
860 // write all samples per track
861 while (sample_number < samples_total_per_track) {
866 * Because we have and write a fix number of audio streams to SDI board:
867 * we have a actual number of real audio tracks and a rest number of pseudo tracks
870 while (stream_number < audio_streams) {
872 // write for every stream n samples
873 // n = number of channels per stream
875 while (written_bytes < bytes_total) {
876 written_bytes += write(fh_sdi_audio, (uint8_t *) aBuffer[stream_number] + sample_number * bytes_total + written_bytes, bytes_total
879 sum_written_bytes += written_bytes;
880 sum_written_bytes_a += written_bytes;
885 // write pseudo tracks
886 // now fill rest of audio tracks with NULL or copy of first track
887 while (stream_number < 4) { // TODO linsys board model 193 have a limit to 4 AES groups (=4streams,8channels)
889 // write for every stream n samples
890 // n = number of channels per stream
892 while (written_bytes < bytes_total) {
893 written_bytes += write(fh_sdi_audio, (uint8_t *) aBuffer[0] + sample_number * bytes_total + written_bytes, bytes_total - written_bytes);
895 sum_written_bytes += written_bytes;
896 sum_written_bytes_b += written_bytes;
903 // // Check for events of the SDI board (only firmware 0.9)
905 // if (ioctl(fh_sdi_audio, SDI_IOC_TXGETEVENTS, &val) < 0) {
906 // //Maybe this is not an SDI device...
907 // fprintf(stderr, "SDI AUDIO output:");
908 // perror("unable to get the transmitter event flags");
910 // if (val & SDI_EVENT_TX_BUFFER) {
911 // printf("SDI AUDIO driver transmit buffer queue underrun "
914 // if (val & SDI_EVENT_TX_FIFO) {
915 // printf("SDI AUDIO onboard transmit FIFO underrun detected.\n");
918 // if (val & SDI_EVENT_TX_DATA) {
919 // printf("SDI AUDIO transmit data change detected.\n");
925 return getDBN(my_DBN);
926 } // end sdimaster_playout()
929 //****************************************************************************************
930 //*************************** Create Line **********************************************
931 //****************************************************************************************
933 /** generate one SDI line
934 * @param *buf: buffer to hold the line
935 * @param field: size of the video Buffer
936 * @param active: v-blank or active-video
937 * @param *video_buffer: video buffer
938 * @param *audio_buffer2: 1.audio buffer ch1-ch2
939 * @param *audio_buffer1: 2.audio buffer ch2-ch3
940 * @param line: linenumber
941 * @param AudioGroupCounter: count written AudioGroup
942 * @param AudioGroups2Write: number of samples to write
943 * @param audio_streams: number of audio streams to integrate
945 static inline int create_SD_SDI_Line(uint16_t *buf, const struct line_info *info, int field, int active, uint8_t *video_buffer,
946 int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], int linenumber_sdiframe, int active_video_line, int my_DBN, int16_t AudioGroupCounter,
947 int16_t AudioGroups2Write, int audio_streams) {
949 // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2)
950 // *************************************************************************
951 // 625 lines: | EAV | ANC | SAV | [CbY1CrY2] |
952 // *************************************************************************
953 // 1728 SDI-words: | 4 | 280 | 4 | 720+360+360=1440 |
954 // *************************************************************************
956 // points to current position in line
959 //#########################################################################################
960 /* TRS Timing Reference Signal for EAV
970 *p++ = info->xyz->eav;
971 //#########################################################################################
973 /* ANC Ancillary Data with AES
975 * [ADF][ADF][ADF][DID][DBN][DC][UDW]...[UDW][CS]
978 // write ANC Data and get number of samples are written
979 // step with `p` += to the number of written samples
981 //printf("audio_streams:%i\n",audio_streams);
983 // 1 stream, Audio Group 1 with AES Frame 1 - 2
984 if (audio_streams == 1) {
985 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[0], AudioGroupCounter, AudioGroups2Write);
987 // 2 streams, Audio Group 1 with AES Frame 1 - 2
988 if (audio_streams == 2) {
989 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
991 // 3 streams, Audio Group 2 with AES Frame 1 - 4
992 if (audio_streams == 3) {
993 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
994 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[2], AudioGroupCounter, AudioGroups2Write);
996 // 4 streams, Audio Group 2 with AES Frame 1 - 4
997 if (audio_streams == 4) {
998 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
999 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1001 // 5 streams, Audio Group 3 with AES Frame 1 - 6
1002 if (audio_streams == 5) {
1003 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1004 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1005 p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[4], AudioGroupCounter, AudioGroups2Write);
1007 // 6 streams, Audio Group 3 with AES Frame 1 - 6
1008 if (audio_streams == 6) {
1009 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1010 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1011 p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write);
1013 // 7 streams, Audio Group 4 with AES Frame 1 - 7
1014 if (audio_streams == 7) {
1015 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1016 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1017 p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write);
1018 p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[6], AudioGroupCounter, AudioGroups2Write);
1020 // 8 streams, Audio Group 4 with AES Frame 1 - 7
1021 if (audio_streams == 8) {
1022 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1023 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1024 p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write);
1025 p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[7], AudioGroupCounter, AudioGroups2Write);
1028 // Fill ANC data in until the end (position(p) to `ANCILLARY_DATA_SAMPLES`)
1029 while (p < (buf + ANCILLARY_DATA_SAMPLES + 4)) {
1030 // video color: black
1034 //#########################################################################################
1035 // TRS Timing Reference Signal for SAV
1039 *p++ = info->xyz->sav;
1040 //#########################################################################################
1042 // If VBlank then fill the line with 0x200 and 0x040 (total black)
1046 while (p < (buf + info->fmt->samples_per_line)) {
1053 // Insert the video into the line
1054 while (p < (buf + info->fmt->samples_per_line)) { // fill the rest of the line with active video
1056 // shift "<< 2" because 8 bit data in 10 bit word
1058 // Because we skip the first line of video, it can happen that we read too far in the buffer
1059 if (active_video_line >= info->fmt->active_lines_per_frame) {
1060 active_video_line = info->fmt->active_lines_per_frame - 1; // in SD PAL was set 575
1063 *p = video_buffer[(active_video_line * 1440) + ((p - 288) - buf) + 1] << 2; // Cb
1065 if (*(p - 1) < 0x040)
1066 *(p - 1) = 0x040; // check values
1067 if (*(p - 1) > 0x3c0)
1069 *p = video_buffer[(active_video_line * 1440) + ((p - 288) - buf) - 1] << 2; // Y1
1071 if (*(p - 1) < 0x040)
1073 if (*(p - 1) > 0x3ac)
1075 *p = video_buffer[(active_video_line * 1440) + ((p - 288) - buf) + 1] << 2; // Cr
1077 if (*(p - 1) < 0x040)
1079 if (*(p - 1) > 0x3c0)
1081 *p = video_buffer[(active_video_line * 1440) + ((p - 288) - buf) - 1] << 2; // Y2
1083 if (*(p - 1) < 0x040)
1085 if (*(p - 1) > 0x3ac)
1095 * create_HD_SDI_Line - generate one line
1096 * @buf: pointer to a buffer
1097 * @info: pointer to a line information structure
1098 * @active_video_line
1100 * @video_buffer: pattern
1102 * Returns a negative error code on failure and zero on success.
1104 static inline int create_HD_SDI_Line(uint16_t *buf, const struct line_info *info, uint16_t active_video_line, unsigned int active, uint8_t *video_buffer) {
1105 uint16_t *p = buf, *endp, ln;
1106 uint16_t samples = info->blanking ? info->fmt->samples_per_line : info->fmt->active_samples_per_line;
1108 if (info->blanking) {
1110 // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2)
1112 // *************************************************************************
1113 // 625 lines: | EAV | ANC | SAV | [CbY1CrY2] |
1114 // *************************************************************************
1115 // 1728 SDI-words: | 4 | 280 | 4 | 720+360+360=1440 |
1116 // *************************************************************************
1118 // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2)
1119 // Example HD 1080i:
1120 // *************************************************************************
1121 // 1125 lines: | EAV | LN | CRC | ANC | SAV | [CbY1CrY2] |
1122 // *************************************************************************
1123 // 5280 SDI-words: | 6 | 4 | 4 | 280 | 6 | 1920+720+720=3840 |
1124 // *************************************************************************
1126 if (info->fmt == &FMT_576i50) {
1131 *p++ = info->xyz->eav;
1140 *p++ = info->xyz->eav;
1141 *p++ = info->xyz->eav;
1143 ln = ((info->ln & 0x07f) << 2) | (~info->ln & 0x040) << 3;
1146 ln = ((info->ln & 0x780) >> 5) | 0x200;
1149 /* CRC, added by serializer */
1157 /* Horizontal blanking */
1158 while (p < (buf + info->fmt->samples_per_line - info->fmt->active_samples_per_line - 4)) {
1165 if (info->fmt == &FMT_576i50) {
1170 *p++ = info->xyz->sav;
1179 *p++ = info->xyz->sav;
1180 *p++ = info->xyz->sav;
1189 while (p < (buf + samples)) {
1200 while (p < (buf + samples)) {
1202 if (active_video_line >= info->fmt->active_lines_per_frame) {
1203 active_video_line = info->fmt->active_lines_per_frame - 1;
1206 // sample = (active_video_line * info->fmt->active_samples_per_line) + (p - buf) + 1;
1207 // *p++ = sample > 1440 ? 735 : (video_buffer[sample] << 2);
1208 // sample = (active_video_line * info->fmt->active_samples_per_line) + (p - buf) - 1;
1209 // *p++ = sample > 1440 ? 335 : (video_buffer[sample] << 2);
1210 // sample = (active_video_line * info->fmt->active_samples_per_line) + (p - buf) + 1;
1211 // *p++ = sample > 1440 ? 793 : (video_buffer[sample] << 2);
1212 // sample = (active_video_line * info->fmt->active_samples_per_line) + (p - buf) - 1;
1213 // *p++ = sample > 1440 ? 335 : (video_buffer[sample] << 2);
1215 *p = video_buffer[(active_video_line * info->fmt->active_samples_per_line) + (p - buf) + 1] << 2; // Cb
1217 // check values, but need manny resources
1218 // if (*(p - 1) < 0x040)
1219 // *(p - 1) = 0x040;
1220 // if (*(p - 1) > 0x3c0)
1221 // *(p - 1) = 0x3c0;
1223 *p = video_buffer[(active_video_line * info->fmt->active_samples_per_line) + (p - buf) - 1] << 2; // Y1
1225 // if (*(p - 1) < 0x040)
1226 // *(p - 1) = 0x040;
1227 // if (*(p - 1) > 0x3ac)
1228 // *(p - 1) = 0x3ac;
1230 *p = video_buffer[(active_video_line * info->fmt->active_samples_per_line) + (p - buf) + 1] << 2; // Cr
1232 // if (*(p - 1) < 0x040)
1233 // *(p - 1) = 0x040;
1234 // if (*(p - 1) > 0x3c0)
1235 // *(p - 1) = 0x3c0;
1237 *p = video_buffer[(active_video_line * info->fmt->active_samples_per_line) + (p - buf) - 1] << 2; // Y2
1239 // if (*(p - 1) < 0x040)
1240 // *(p - 1) = 0x040;
1241 // if (*(p - 1) > 0x3ac)
1242 // *(p - 1) = 0x3ac;
1250 static int writeANC(uint16_t *p, int videoline_sdiframe, uint16_t DID, int my_DBN, int16_t *audio_buffer_A, int16_t *audio_buffer_B, int16_t AudioGroupCounter,
1251 int16_t AudioGroups2Write) {
1254 * ANC Ancillary Data (vgl. SMPTE 291-M page 6 )
1255 * [ADF][ADF][ADF][DID][DBN][DC][UDW]...[UDW][CS]
1259 // save only current position for return value
1261 // 16bit buffer to write temporarily 10bit word
1262 uint16_t buffer = 0; // set all explicit to zero, special the bit9 for parity
1264 int8_t parity_counter = 0;
1266 if (AudioGroups2Write > 0) {
1268 // 3 ADF (Ancillary Data Flag)
1273 // 1 DID (Data Identification)
1274 // save DID for checker()
1275 uint16_t *DID_pointer = p;
1276 *p++ = DID;// (AES Audio Data, Group
1277 // *p++ = 0x2FF; // (AES Audio Data, Group1=0x2FF)
1278 // *p++ = 0x1FD; // (AES Audio Data, Group2=0x1FD)
1279 // *p++ = 0x1FB; // (AES Audio Data, Group3=0x1FB)
1280 // *p++ = 0x2F9; // (AES Audio Data, Group4=0x2F9)
1282 // 1 DBN (Data Block Number) inactiv: 1000000000 b9,b8,b7-b0 ; SMPTE 272-M chapter15.1
1285 // 1 DBN (dynamic version0.1-beta ), should start with previus DBN of SDI-Frame
1286 // -need "previus DBN" or "current framenumber"
1288 // [1] [1] << start sdi frame
1299 // [625] [115] << end sdi frame
1300 // [1] [116] << start sdi frame
1301 // Accuracy of videoline_sdiframe(1 up to 625) to 8bit (1-255)
1302 //buffer = ((videoline_sdiframe-1) % 255)+1;
1305 // count binary ones for parity
1307 for (i = 0; i < 8; i++) {
1308 if (buffer & (1 << i))
1311 if ((parity_counter % 2) == 0) { //else leave the 0
1312 buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1314 buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1318 // 1 DC (Data Counter)
1319 // number of UDW = AudioGroups2Write x 2AESFrames x 2channesl x 3words(X,X+1,X+2)
1320 buffer = AudioGroups2Write * 2* 2* 3 ; parity_counter= 0;
1321 // count binary ones for parity
1322 for (i=0; i<8; i++) {
1323 if (buffer & (1 << i))
1326 if ((parity_counter%2)==0) { //else leave the 0
1327 buffer+= 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1329 buffer+= 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1333 int16_t sample_number=0;
1334 int16_t counter = 0;
1336 // = n x 1 AudioGroup
1337 // = n x 2 x 1AESFrame
1338 // = n x 2 x 2samples
1341 while (counter < AudioGroups2Write*2) { /* 4:3 */
1343 // write one Audio Group with 4 x AES subframes
1344 // ( samples for ch01,ch02,ch03,ch04 or ch05,ch06,ch07,ch08 or ch09,ch10,ch11,ch12 or ch13,ch14,ch15,ch16)
1345 // and use audio_buffer_A(stereo) and audio_buffer_B(stereo)
1346 // `pack_AES_subframe()` write 3 ANC words (3*10bit), also 1 sample
1348 sample_number=(AudioGroupCounter*2)+ counter;
1349 pack_AES_subframe(p, getChannelStatusBit(sample_number/2, 1),
1350 getZBit(sample_number/2), 0, &audio_buffer_A[sample_number]); // left
1351 p+=3; // step 3 words
1353 sample_number=(AudioGroupCounter*2)+ counter+1;
1354 pack_AES_subframe(p, getChannelStatusBit(sample_number/2, 2),
1355 getZBit(sample_number/2), 1, &audio_buffer_A[sample_number]); // right
1358 sample_number=(AudioGroupCounter*2)+ counter;
1359 pack_AES_subframe(p, getChannelStatusBit(sample_number/2, 3),
1360 getZBit(sample_number/2), 2, &audio_buffer_B[sample_number]); // left
1363 sample_number=(AudioGroupCounter*2)+ counter+1;
1364 pack_AES_subframe(p, getChannelStatusBit(sample_number/2, 4),
1365 getZBit(sample_number/2), 3, &audio_buffer_B[sample_number]); // right
1370 // 1 CS (Checksum from DID - UDW)
1371 *p++ = checker(DID_pointer);
1373 // fill ANC with one dummy for videocolor black
1374 // rest until end of `ANCILLARY_DATA_SAMPLES` will be fill in a loop after call this function
1380 // calculate checksumm of ANC (SMPTE 272-M 15.3 Checksum (CS))
1381 static uint16_t checker(uint16_t *DID_pointer) {
1386 // DID - Datablock Identification
1387 cs += (*DID_pointer++) & 0x1FF; // 9 x LSB
1389 // DBN - Datablock Number
1390 cs += (*DID_pointer++) & 0x1FF; // 9 x LSB
1393 cs += (*DID_pointer) & 0x1FF; // 9 x LSB
1395 // store address of DC an ad to the real value of DC
1396 // DataCounter store
1397 // ´ende´ point to DataCounter
1398 uint16_t *ende = DID_pointer;
1399 // ´ende´ point to last field
1400 ende += (*DID_pointer) & 0xFF; // without parity-Bit and ¬9-Bit
1404 // while DID_pointer point to smaller addres like 'ende'
1405 while (DID_pointer <= ende) {
1406 cs += (*DID_pointer++) & 0x1FF; // 9 x LSB
1409 // limit to 9Bit, because of overflow of sum
1412 // set bit10 NOT bit9:
1414 // - & with bitmask '01 0000 0000'
1415 // - shift rest (1xbit)to left
1417 cs += ((~cs) & 0x100) << 1;
1424 * pack 16bit in AES subframe with 3 words (30 bit) and write in ´*p´
1425 * 10bit-words --> [X],[X+1], [X+2] implements 20bit for audio
1427 * BIT 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
1428 * ##### ### ### ### ### ### ### ### ### ###
1429 * [X] : [ !bit8, a5, a4, a3, a2, a1, a0, ch0, ch1, z ],
1430 * [X+1] : [ !bit8, a14, a13, a12, a11, a10, a9, a8, a7 , a6 ],
1431 * [X+2] : [ !bit8, P, C, U, V, a19, a18, a17, a16, a15 ]
1433 * @param *p: Pointer to SDI frame buffer
1434 * @param c: value of AES subframe Channel Status Bit
1435 * @param z: value of AES subframe
1436 * @param ch: channel od AES subframe (value:0,1,2,3)
1437 * @param *audio_samplex: pointer to the audio buffer
1439 static int pack_AES_subframe(uint16_t *p, int8_t c, int8_t z, int8_t ch, int16_t *audio_samplex) {
1442 * NOTE: WE JUST SUPPORT ONLY 16BIT SAMPLE SIZE
1445 // push 16bit up to 20bit(32bit)
1446 int32_t audio_sample = *audio_samplex;
1447 audio_sample = audio_sample << 4; // Shift by 4 (louder)
1450 int8_t parity_counter = 0;
1452 // 16bit buffer to write 10bit of [X]word,[X+1]word,[X+2]word,
1453 uint16_t buffer = 0;
1455 //#########################################################
1456 //### WORD X ############################################
1457 //#########################################################
1458 // word X: !bit8, a5, a4, a3, a2, a1, a0, ch1, ch0, z
1460 buffer = z; // z bit every 192bit = 1
1461 buffer += ch << 1; // ch1 - ch0
1462 buffer += (audio_sample & 0x3f) << 3; // a5 - a0
1463 buffer += ((~buffer) & 0x100) << 1; // !bit8
1470 for (i = 0; i < 9; i++) {
1471 if (buffer & 1 << i)
1475 //#########################################################
1476 //### WORD X+1 ############################################
1477 //#########################################################
1478 // word X+1: !bit8, a14, a13, a12, a11, a10, a9, a8, a7, a6
1481 buffer += (audio_sample >> 6) & 0x1ff; // a14 - a6
1482 buffer += ((~buffer) & 0x100) << 1; // !bit8
1487 // count ones (zähle Einsen)
1489 for (i = 0; i < 9; i++) {
1490 if (buffer & 1 << i)
1494 //#########################################################
1495 //### WORD X+2 ############################################
1496 //#########################################################
1497 // word X+2: !bit8, P, C, U, V, a19, a18, a17, a16, a15
1500 buffer += (audio_sample >> 15) & 0x01F; // a15 - a19
1501 // default of [V][U][C] bits = `0`
1502 //buffer += 1<<5; // V (AES sample validity bit)
1503 //buffer += 1<<6; // U (AES user bit)
1504 //buffer += 1<<7; // C (AES audio channel status bit)
1505 buffer += c << 7; // C (AES audio channel status bit)
1507 // count ones (zähle Einsen)
1508 for (i = 0; i < 8; i++) {
1509 if (buffer & 1 << i)
1513 // if (!parity_counter%2) //else leave the 0
1514 // buffer+= 1 << 8; // P (AES even parity bit)
1516 // buffer += ((~buffer) & 0x100 )<<1; // !bit8
1517 if ((parity_counter % 2) == 0) { //else leave the 0
1518 buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1520 buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1530 static uint8_t getZBit(int sample_number) {
1532 // start in SDI line 6 also 18samples later
1533 //sample_number+=192-18;
1535 if (sample_number % 192 == 0) {
1536 //printf("1 %i\n", sample_number);
1544 static uint8_t getChannelStatusBit(uint16_t sample_number, uint8_t ch) {
1547 uint8_t AESChannelStatusBit = 0;
1549 // start in SDI line 6 also 18samples later
1550 //AESChannelStatusBit=((sample_number+192-18)%192);
1551 // interval in 192bit
1552 AESChannelStatusBit = sample_number % 192;
1554 // when mulichannelmode is true
1555 if (AESChannelStatusBitArray[31] == 1) {
1556 // set bits for channel
1557 if (AESChannelStatusBit == 30 && ch == 2)
1559 if (AESChannelStatusBit == 30 && ch == 4)
1561 if (AESChannelStatusBit == 29 && (ch == 4))
1563 if (AESChannelStatusBit == 29 && (ch == 3))
1566 return AESChannelStatusBitArray[AESChannelStatusBit];
1569 static int16_t getNumberOfAudioGroups2Write(int linenumber) {
1571 // `4:3_VTR`-distribution
1572 if (linenumber >= 11 && linenumber <= 95) {
1573 if ((linenumber - 11) % 14 == 0) {
1578 } else if (linenumber >= 108 && linenumber <= 220) {
1579 if ((linenumber - 10) % 14 == 0) {
1584 } else if (linenumber >= 233 && linenumber <= 345) {
1585 if ((linenumber - 9) % 14 == 0) {
1590 } else if (linenumber >= 358 && linenumber <= 470) {
1591 if ((linenumber - 8) % 14 == 0) {
1596 } else if (linenumber >= 483 && linenumber <= 595) {
1597 if ((linenumber - 7) % 14 == 0) {
1602 } else if (linenumber >= 608 && linenumber <= 622) {
1603 if ((linenumber - 6) % 14 == 0) {
1612 // // `4:3`-distribution
1613 // if(linenumber<=315){
1614 // if(linenumber>=6 && linenumber<=8){
1617 // if((linenumber+5)%10==0){
1623 // if(linenumber>=319 && linenumber<=321){
1626 // if((linenumber-8)%10==0){
1633 // // full-distribution
1634 // if(linenumber<=45){
1640 // // fullhalf-distribution
1641 // if (linenumber==625)
1644 // if (linenumber%14==0) {
1651 static uint8_t getDBN(int my_DBN) {
1653 return ((my_DBN - 1) % 255) + 1;
1657 * pack8 - pack a line of 8-bit data
1658 * @outbuf: pointer to the output buffer
1659 * @inbuf: pointer to the input buffer
1660 * @count: number of elements in the buffer
1662 * Returns a pointer to the next output location.
1664 static inline uint8_t *
1665 pack8(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
1666 uint16_t *inp = inbuf;
1667 uint8_t *outp = outbuf;
1669 while (inp < (inbuf + count)) {
1670 *outp++ = *inp++ >> 2;
1676 * pack10 - pack a line of 10-bit data
1677 * @outbuf: pointer to the output buffer
1678 * @inbuf: pointer to the input buffer
1679 * @count: number of elements in the buffer
1681 * Returns a pointer to the next output location.
1683 static inline uint8_t * pack10(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
1685 uint16_t *inp = inbuf;
1686 uint8_t *outp = outbuf;
1688 while (inp < (inbuf + count)) {
1689 *outp++ = *inp & 0xff;
1690 *outp = *inp++ >> 8;
1691 *outp++ += (*inp << 2) & 0xfc;
1692 *outp = *inp++ >> 6;
1693 *outp++ += (*inp << 4) & 0xf0;
1694 *outp = *inp++ >> 4;
1695 *outp++ += (*inp << 6) & 0xc0;
1696 *outp++ = *inp++ >> 2;
1702 * pack_v210 - pack a line of v210 data
1703 * @outbuf: pointer to the output buffer
1704 * @inbuf: pointer to the input buffer
1705 * @count: number of elements in the buffer
1707 * Returns a pointer to the next output location.
1709 static inline uint8_t * pack_v210(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
1711 uint16_t *inp = inbuf;
1712 uint8_t *outp = outbuf;
1714 count = (count / 96) * 96 + ((count % 96) ? 96 : 0);
1715 while (inp < (inbuf + count)) {
1716 *outp++ = *inp & 0xff;
1717 *outp = *inp++ >> 8;
1718 *outp++ += (*inp << 2) & 0xfc;
1719 *outp = *inp++ >> 6;
1720 *outp++ += (*inp << 4) & 0xf0;
1721 *outp++ = *inp++ >> 4;
1727 static int sdimaster_close() {
1733 close(fh_sdi_audio);
1735 close(fh_sdi_video);
1741 * mkline - generate one line
1742 * @buf: pointer to a buffer
1743 * @info: pointer to a line information structure
1746 * Returns a negative error code on failure and zero on success.
1748 static int mkline(unsigned short int *buf, const struct line_info *info, unsigned int pattern) {
1749 const unsigned int b = 205;
1750 unsigned short int *p = buf, *endp;
1751 unsigned int samples = info->blanking ? info->fmt->samples_per_line : info->fmt->active_samples_per_line;
1753 if (info->blanking) {
1758 *p++ = info->xyz->eav;
1759 /* Horizontal blanking */
1760 while (p < (buf + 272)) {
1770 *p++ = info->xyz->sav;
1777 while (p < (buf + samples)) {
1785 while (p < (buf + samples)) {
1842 while (p < (buf + samples)) {
1899 while (p < (buf + samples)) {
1939 /* blacker than black */
1955 /* whiter than black */
1964 while (p < (buf + samples)) {