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, const struct audio_format * audio_format) {
137 device_file_video = device_video;
138 device_file_audio = device_audio;
140 // set flag for using of blanking with ancillary data
141 info.blanking = blanking;
143 // set pack method 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 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080I_60HZ;
153 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001
154 && myProfile->progressive == 0) {
155 info.fmt = &FMT_1080i5994;
156 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080I_59_94HZ;
157 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
158 && myProfile->progressive == 0) {
159 info.fmt = &FMT_1080i50;
160 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080I_50HZ;
161 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1
162 && myProfile->progressive == 1) {
163 info.fmt = &FMT_1080p30;
164 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_30HZ;
165 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001
166 && myProfile->progressive == 1) {
167 info.fmt = &FMT_1080p2997;
168 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_29_97HZ;
169 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
170 && myProfile->progressive == 1) {
171 info.fmt = &FMT_1080p25;
172 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_25HZ;
173 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 24 && myProfile->frame_rate_den == 1
174 && myProfile->progressive == 1) {
175 info.fmt = &FMT_1080p24;
176 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_24HZ;
177 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 24000 && myProfile->frame_rate_den == 1001
178 && myProfile->progressive == 1) {
179 info.fmt = &FMT_1080p2398;
180 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_23_98HZ;
181 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 60 && myProfile->frame_rate_den == 1
182 && myProfile->progressive == 1) {
183 info.fmt = &FMT_720p60;
184 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_60HZ;
185 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 60000 && myProfile->frame_rate_den == 1001
186 && myProfile->progressive == 1) {
187 info.fmt = &FMT_720p5994;
188 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_59_94HZ;
189 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 50 && myProfile->frame_rate_den == 1
190 && myProfile->progressive == 1) {
191 info.fmt = &FMT_720p50;
192 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_50HZ;
193 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1
194 && myProfile->progressive == 1) {
195 info.fmt = &FMT_720p30;
196 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_30HZ;
197 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001
198 && myProfile->progressive == 1) {
199 info.fmt = &FMT_720p2997;
200 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_29_97HZ;
201 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
202 && myProfile->progressive == 1) {
203 info.fmt = &FMT_720p25;
204 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_25HZ;
205 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 24 && myProfile->frame_rate_den == 1
206 && myProfile->progressive == 1) {
207 info.fmt = &FMT_720p24;
208 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_24HZ;
209 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 24000 && myProfile->frame_rate_den == 1001
210 && myProfile->progressive == 1) {
211 info.fmt = &FMT_720p2398;
212 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_23_98HZ;
213 } else if (myProfile->width == 720 && myProfile->height == 576 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
214 && myProfile->progressive == 0) {
215 info.fmt = &FMT_576i50;
216 sdi_frame_mode = SDIVIDEO_CTL_BT_601_576I_50HZ;
217 } else if (myProfile->width == 720 && myProfile->height == 480 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001
218 && myProfile->progressive == 0) {
219 info.fmt = &FMT_480i5994;
220 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_125M_486I_59_94HZ;
222 printf("Consumer got unknown format: %s", myProfile->description);
223 info.fmt = &FMT_576i50;
224 sdi_frame_mode = SDIVIDEO_CTL_BT_601_576I_50HZ;
227 printf("Consumer use format: %s\nProfile: %i %i %i %i %i\n", myProfile->description, myProfile->width, myProfile->height, myProfile->frame_rate_num,
228 myProfile->frame_rate_den, myProfile->progressive);
230 // Check if the format supports own blanking (note: model 193 supports currently only active video at the video device file)
231 if (info.blanking && info.fmt != &FMT_576i50) {
232 printf("SDI consumer doesn't support blanking(HANC) for the configured SD board and SDI format. Try argument: blanking=false\n");
236 // if we write our own HANC we need an AES channel status bit array
240 // http://www.sencore.com/newsletter/Nov05/DigAudioChannelStatusBits.htm
242 // http://www.sencore.com/uploads/files/DigAudioChannelStatusBits.pdf
244 // create empty AESChannelStatusBitArray
246 for (i = 0; i < sizeof(AESChannelStatusBitArray) / sizeof(AESChannelStatusBitArray[0]); i++)
247 AESChannelStatusBitArray[i] = 0;
250 * Professional Format - Channel Status Bits
253 AESChannelStatusBitArray[0] = 1; // professional format
255 AESChannelStatusBitArray[1] = 0; // PCM Format
257 AESChannelStatusBitArray[2] = 1; // Emphasis: [100] No Emphasis
258 AESChannelStatusBitArray[3] = 0; // ^
259 AESChannelStatusBitArray[4] = 0; // ^
261 AESChannelStatusBitArray[5] = 0; // locked
263 AESChannelStatusBitArray[6] = 0; // sample frequency Fs: [01]48kHz, [10]44kHz, [11]32kHz
264 AESChannelStatusBitArray[7] = 1; // ^
266 AESChannelStatusBitArray[8] = 0; // channel mode: [0000] not indicated, [0001]2channels, [0010]1channel mono, ...
267 AESChannelStatusBitArray[9] = 0; // ^
268 AESChannelStatusBitArray[10] = 0; // ^
269 AESChannelStatusBitArray[11] = 1; // ^
271 AESChannelStatusBitArray[19] = 0; // Encoded sample word length [100]20bits,
272 AESChannelStatusBitArray[20] = 0; //
273 AESChannelStatusBitArray[21] = 0; //
275 AESChannelStatusBitArray[24] = 0; //
276 AESChannelStatusBitArray[25] = 0; //
277 AESChannelStatusBitArray[26] = 0; //
278 AESChannelStatusBitArray[27] = 0; //
279 AESChannelStatusBitArray[28] = 0; //
280 AESChannelStatusBitArray[29] = 0; //
281 AESChannelStatusBitArray[30] = 0; //
282 AESChannelStatusBitArray[31] = 0; // Multi Channel Mode
283 ////// Byte 4-21 //////
284 //AESChannelStatusBitArray[32-179]= 0;
285 ////// Byte 22 //////
286 AESChannelStatusBitArray[180] = 0; // Reliability Flags
287 AESChannelStatusBitArray[181] = 1; // ^
288 AESChannelStatusBitArray[182] = 1; // ^
289 AESChannelStatusBitArray[183] = 1; // ^
290 ////// Byte 23 //////
291 AESChannelStatusBitArray[184] = 0; // Cyclic Redundancy Check
292 AESChannelStatusBitArray[185] = 1; // ^
293 AESChannelStatusBitArray[186] = 0; // ^
294 AESChannelStatusBitArray[187] = 0; // ^
295 AESChannelStatusBitArray[188] = 1; // ^
296 AESChannelStatusBitArray[189] = 0; // ^
297 AESChannelStatusBitArray[190] = 1; // ^
298 AESChannelStatusBitArray[191] = 1; // ^
301 // set buffer for one line of active video samples
302 line_buffer = (uint16_t*) calloc(info.fmt->samples_per_line, sizeof(uint16_t));
304 // calculate and set buffer for the complete SDI frame
305 if (info.fmt != &FMT_576i50 && info.fmt != &FMT_480i5994) {
307 if (pack == pack_v210) {
308 samples = (info.fmt->samples_per_line / 96 * 48) + ((info.fmt->samples_per_line % 96) ? 48 : 0);
309 sdi_frame_size = samples * info.fmt->lines_per_frame * 8 / 3;
311 sdi_frame_size = info.fmt->samples_per_line * info.fmt->lines_per_frame;
314 if (pack == pack_v210) {
315 samples = (info.fmt->active_samples_per_line / 96 * 48) + ((info.fmt->active_samples_per_line % 96) ? 48 : 0);
316 sdi_frame_size = samples * info.fmt->active_lines_per_frame * 8 / 3;
318 sdi_frame_size = info.fmt->active_samples_per_line * info.fmt->active_lines_per_frame;
323 if (pack == pack_v210) {
324 sdi_frame_size = info.fmt->samples_per_line * 4 / 3 * info.fmt->lines_per_frame;
325 } else if (pack == pack8) {
326 sdi_frame_size = info.fmt->samples_per_line * info.fmt->lines_per_frame;
328 sdi_frame_size = info.fmt->samples_per_line * 10 / 8 * info.fmt->lines_per_frame;
331 if (pack == pack_v210) {
332 sdi_frame_size = info.fmt->active_samples_per_line * 4 / 3 * info.fmt->active_lines_per_frame;
333 } else if (pack == pack8) {
334 sdi_frame_size = info.fmt->active_samples_per_line * info.fmt->active_lines_per_frame;
336 sdi_frame_size = info.fmt->active_samples_per_line * 10 / 8 * info.fmt->active_lines_per_frame;
341 // (*10/8 because we store (TOTAL_SAMPLES*TOTAL_LINES) words with 10 bit in this 8 bit array) )
342 if (info.fmt == &FMT_576i50 && info.blanking) {
343 sdi_frame_size = info.fmt->samples_per_line * 10 / 8 * info.fmt->lines_per_frame;
347 printf("SDI frame size: %li\n", sdi_frame_size);
349 printf("Frame size for active video: %li\n", sdi_frame_size);
353 * Setup HD-SDI Master device (vidport):
355 * if device_file_video available then
356 * if vidport available
359 * 1. open device file handler
361 * if device_file_audio available then
363 * 2. open device file handler
367 if (device_file_video != NULL) {
369 // If we use a Linsys HD board with active video (without blanking) setup the board for the used mode
370 if (strstr(device_file_video, "sdivideotx") != NULL && !info.blanking) {
375 value = itoa(sdi_frame_size);
376 setSDIVideoProperties(SETTING_BUFFER_SIZE_VIDEO, value, device_video);
380 value = itoa(sdi_frame_mode);
381 setSDIVideoProperties(SETTING_FRAME_MODE, value, device_video);
386 setSDIVideoProperties(SETTING_DATA_MODE, "0", device_video);
387 else if (pack == pack_v210)
388 setSDIVideoProperties(SETTING_DATA_MODE, "1", device_video);
391 // open file handle for SDI(video) output
392 if ((fh_sdi_video = open(device_file_video, O_WRONLY)) == -1) {
394 printf("\ncould not open video output destination: %s\n", device_file_video);
397 printf("SDI consumer uses video device file: %s\n", device_file_video);
399 // Check if we have to use a separate device file for audio
400 if (device_file_audio != NULL) {
402 // set settings for audio device file
403 if (strstr(device_file_audio, "sdiaudiotx") != NULL && !info.blanking) {
408 * prepare sample size
409 * MLT suports: 16bit, 32bit
410 * LINSYS SDI boards supports: 16bit, 24bit, 32bit
411 * we set 16bit as default
413 uint8_t sample_size = audio_format->aformat == mlt_audio_s32 ? 32 : 16;
416 // audio buffer per frame (Bytes) = sample rate / frame rate * ( sample size / 1Byte ) x channels
417 value = itoa(audio_format->sample_rate / (myProfile->frame_rate_num / myProfile->frame_rate_den) * sample_size / 8 * audio_format->channels );
418 setSDIAudioProperties(SETTING_BUFFER_SIZE_AUDIO, value, device_audio);
422 value = itoa(audio_format->channels);
423 setSDIAudioProperties(SETTING_CHANNELS, value, device_audio);
427 value = itoa(audio_format->sample_rate);
428 setSDIAudioProperties(SETTING_SAMPEL_RATE, value, device_audio);
432 value = itoa(sample_size);
433 setSDIAudioProperties(SETTING_SAMPLE_SIZE, value, device_audio);
437 // open file handle for audio output
438 if ((fh_sdi_audio = open(device_file_audio, O_WRONLY)) == -1) {
440 printf("\nCould not open audio output destination: %s\n", device_file_audio);
443 printf("SDI consumer uses audio device file: %s\n", device_file_audio);
448 // set buffer for the complete SDI frame
449 data = (uint8_t*) calloc(sdi_frame_size, sizeof(uint8_t));
455 * Writes video and audio to specified files in SDI format
456 * @param *vBuffer: Pointer to a video Buffer
458 * @param *audio_format: mlt audio_format
459 * @param audio_streams: number of audio streams which have content in aBuffer (available 0-8)
460 * @return current DBN (data block number of SDI frame)
462 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,
465 // Pointer to the start of data. This is used to fill data line by line
468 //*******************************************************************************************
469 //**************** Build the SDI frame line by line ****************************************
470 //*******************************************************************************************
473 * if SDI FMT_576i50 for card ASSY 145 or ASSY 159, with access to whole SDI frame buffer
474 * and device_file_audio must be NULL
475 * than we write own audio data,
477 * than HD for card ASSY 193
479 //if (info.fmt == &FMT_576i50 && device_file_audio == NULL && !strcmp(device_file_video, "/dev/sdivideotx0")) {
480 if (info.fmt == &FMT_576i50 && info.blanking) {
482 //counter for the lines
484 int16_t AudioGroupCounter = 0;
486 /*#####################################################*/
487 /*######## FIELD 1 #######################*/
488 /*#####################################################*/
490 info.xyz = &FIELD_1_VERT_BLANKING;
492 // line 1-22 VERTICAL_BLANKING:23 lines SAV 0x2ac EAV 0x2d8
493 for (i = 1; i <= 5; i++) {
494 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
495 getNumberOfAudioGroups2Write(i), audio_streams);
496 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
497 p = pack10(p, line_buffer, info.fmt->samples_per_line);
499 for (i = 6; i <= 8; i++) {
500 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
501 getNumberOfAudioGroups2Write(i), audio_streams);
502 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
503 p = pack10(p, line_buffer, info.fmt->samples_per_line);
505 for (i = 9; i <= 22; i++) {
506 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
507 getNumberOfAudioGroups2Write(i), audio_streams);
508 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
509 p = pack10(p, line_buffer, info.fmt->samples_per_line);
511 // line 23-310 ACTIVE: 287 lines SAV 0x200 EAV 0x274
512 info.xyz = &FIELD_1_ACTIVE;
513 int f1counter = 1; // only odd lines
514 for (i = 23; i <= 310; i++) {
515 create_SD_SDI_Line(line_buffer, &info, FIELD_1, ACTIVE_VIDEO, vBuffer, aBuffer, i, f1counter, getDBN(my_DBN++), AudioGroupCounter,
516 getNumberOfAudioGroups2Write(i), audio_streams);
517 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
518 p = pack10(p, line_buffer, info.fmt->samples_per_line);
522 // line 311-312 VERTICAL_BLANKING: 2 lines SAV 0x2ac EAV 0x2d8
523 info.xyz = &FIELD_1_VERT_BLANKING;
524 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
525 getNumberOfAudioGroups2Write(i), audio_streams);
526 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
527 p = pack10(p, line_buffer, info.fmt->samples_per_line);
528 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
529 getNumberOfAudioGroups2Write(i), audio_streams);
530 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
531 p = pack10(p, line_buffer, info.fmt->samples_per_line);
533 /*#####################################################*/
534 /*######## FIELD 2 ########################*/
535 /*#####################################################*/
537 info.xyz = &FIELD_2_VERT_BLANKING;
539 // line 313-336 VERTICAL_BLANKING: 23 lines SAV 0x3b0 EAV 0x3c4
540 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
541 getNumberOfAudioGroups2Write(i), audio_streams);
542 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
543 p = pack10(p, line_buffer, info.fmt->samples_per_line);
545 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
546 getNumberOfAudioGroups2Write(i), audio_streams);
547 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
548 p = pack10(p, line_buffer, info.fmt->samples_per_line);
550 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
551 getNumberOfAudioGroups2Write(i), audio_streams);
552 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
553 p = pack10(p, line_buffer, info.fmt->samples_per_line);
555 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
556 getNumberOfAudioGroups2Write(i), audio_streams);
557 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
558 p = pack10(p, line_buffer, info.fmt->samples_per_line);
560 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
561 getNumberOfAudioGroups2Write(i), audio_streams);
562 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
563 p = pack10(p, line_buffer, info.fmt->samples_per_line);
565 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
566 getNumberOfAudioGroups2Write(i), audio_streams);
567 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
568 p = pack10(p, line_buffer, info.fmt->samples_per_line);
570 // `getAudioGroups2Write()`=0
571 for (i = 319; i <= 321; i++) {
572 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
573 getNumberOfAudioGroups2Write(i), audio_streams);
574 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
575 p = pack10(p, line_buffer, info.fmt->samples_per_line);
577 for (i = 322; i <= 335; i++) {
578 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
579 getNumberOfAudioGroups2Write(i), audio_streams);
580 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
581 p = pack10(p, line_buffer, info.fmt->samples_per_line);
583 // line 336-623 ACTIVE: 288 lines SAV 0x31c EAV 0x368
584 info.xyz = &FIELD_2_ACTIVE;
585 int f2counter = 2; // only even Lines
586 for (i = 336; i <= 623; i++) {
588 create_SD_SDI_Line(line_buffer, &info, FIELD_2, ACTIVE_VIDEO, vBuffer, aBuffer, i, f2counter, getDBN(my_DBN++), AudioGroupCounter,
589 getNumberOfAudioGroups2Write(i), audio_streams);
590 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
591 p = pack10(p, line_buffer, info.fmt->samples_per_line);
594 // line 624-625 VERTICAL_BLANKING: 2 lines SAV 0x3b0 EAV 0x3c4
595 info.xyz = &FIELD_2_VERT_BLANKING;
596 for (i = 624; i <= 625; i++) {
597 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
598 getNumberOfAudioGroups2Write(i), audio_streams);
599 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
600 p = pack10(p, line_buffer, info.fmt->samples_per_line);
603 } else { // use HD board without blanking
605 // start with first even line
606 active_video_line = 1;
608 /* *****************************************
609 * *********** LINE DISTRIBUTION ***********
610 * *****************************************
612 * << decide form of scanning (interlaced || progressive) >>
614 * << decide lines per frame (1125 || 625 || 525) >>
615 * if(1125) 1080x1920 HD
617 * else if(625) 576x720 PAL
619 * else (525) 486x720 NTSC
622 * << decide resolution (1125 || 750) >>
623 * if(1125) 1080x1920 HD
625 * else(750) 720x1280 HD
631 if (info.fmt->interlaced) {
633 /****************************************
635 ****************************************/
637 if (info.fmt->lines_per_frame == 1125) {
640 elements = info.fmt->samples_per_line;
641 info.xyz = &FIELD_1_VERT_BLANKING;
642 for (info.ln = 1; info.ln <= 20; info.ln++) {
643 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
644 p = pack(p, line_buffer, elements);
647 elements = info.fmt->active_samples_per_line;
649 info.xyz = &FIELD_1_ACTIVE;
650 for (info.ln = 21; info.ln <= 560; info.ln++) {
651 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
652 p = pack(p, line_buffer, elements);
653 active_video_line += 2;
656 info.xyz = &FIELD_1_VERT_BLANKING;
657 for (info.ln = 561; info.ln <= 563; info.ln++) {
658 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
659 p = pack(p, line_buffer, elements);
661 info.xyz = &FIELD_2_VERT_BLANKING;
662 for (info.ln = 564; info.ln <= 583; info.ln++) {
663 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
664 p = pack(p, line_buffer, elements);
667 // start with first odd line
668 active_video_line = 2;
670 info.xyz = &FIELD_2_ACTIVE;
671 for (info.ln = 584; info.ln <= 1123; info.ln++) {
672 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
673 p = pack(p, line_buffer, elements);
674 active_video_line += 2;
677 info.xyz = &FIELD_2_VERT_BLANKING;
678 for (info.ln = 1124; info.ln <= 1125; info.ln++) {
679 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
680 p = pack(p, line_buffer, elements);
683 } else if (info.fmt->lines_per_frame == 625) {
685 elements = info.fmt->active_samples_per_line;
687 // start with first even line
688 active_video_line = 1;
691 * Generate an SDI PAL frame
694 info.xyz = &FIELD_1_VERT_BLANKING;
695 for (info.ln = 1; info.ln <= 22; info.ln++) {
696 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
697 p = pack(p, line_buffer, elements);
700 info.xyz = &FIELD_1_ACTIVE;
701 for (info.ln = 23; info.ln <= 310; info.ln++) {
702 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
703 p = pack(p, line_buffer, elements);
704 active_video_line += 2;
707 info.xyz = &FIELD_1_VERT_BLANKING;
708 for (info.ln = 311; info.ln <= 312; info.ln++) {
709 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
710 p = pack(p, line_buffer, elements);
712 info.xyz = &FIELD_2_VERT_BLANKING;
713 for (info.ln = 313; info.ln <= 335; info.ln++) {
714 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
715 p = pack(p, line_buffer, elements);
719 // start with first odd line
720 active_video_line = 2;
722 info.xyz = &FIELD_2_ACTIVE;
723 for (info.ln = 336; info.ln <= 623; info.ln++) {
724 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
725 p = pack(p, line_buffer, elements);
726 active_video_line += 2;
729 info.xyz = &FIELD_2_VERT_BLANKING;
730 for (info.ln = 624; info.ln <= 625; info.ln++) {
731 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
732 p = pack(p, line_buffer, elements);
735 } else if (info.fmt->lines_per_frame == 525) {
738 * Generate an SDI NTSC frame
740 elements = info.fmt->active_samples_per_line;
742 active_video_line = 1;
745 info.xyz = &FIELD_1_VERT_BLANKING;
746 for (info.ln = 1; info.ln <= 15; info.ln++) {
747 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
748 p = pack(p, line_buffer, elements);
750 for (info.ln = 16; info.ln <= 16; info.ln++) {
751 info.xyz = &FIELD_1_ACTIVE;
752 mkline(line_buffer, &info, VERT_BLANKING);
753 p = pack(p, line_buffer, elements);
757 info.xyz = &FIELD_1_ACTIVE;
758 // 3 lines opt. video data
759 for (info.ln = 17; info.ln <= 19; info.ln++) {
760 mkline(line_buffer, &info, BLACK);
761 p = pack(p, line_buffer, elements);
763 for (info.ln = 20; info.ln <= 259; info.ln++) {
764 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
765 p = pack(p, line_buffer, elements);
766 active_video_line += 2;
769 info.xyz = &FIELD_1_VERT_BLANKING;
770 for (info.ln = 260; info.ln <= 261; info.ln++) {
771 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
772 p = pack(p, line_buffer, elements);
774 info.xyz = &FIELD_2_VERT_BLANKING;
775 // 7 lines vertical data
776 for (info.ln = 262; info.ln <= 269; info.ln++) {
777 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
778 p = pack(p, line_buffer, elements);
780 // 9 lines opt. video data ?? // TODO have a look to SMPTE
781 for (info.ln = 270; info.ln <= 278; info.ln++) {
782 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
783 p = pack(p, line_buffer, elements);
788 active_video_line = 0;
789 // 3 lines opt. video data
790 info.xyz = &FIELD_2_ACTIVE;
791 for (info.ln = 279; info.ln <= 281; info.ln++) {
792 mkline(line_buffer, &info, BLACK);
793 p = pack(p, line_buffer, elements);
795 for (info.ln = 282; info.ln <= 521; info.ln++) {
796 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
797 p = pack(p, line_buffer, elements);
798 active_video_line += 2;
801 info.xyz = &FIELD_2_VERT_BLANKING;
802 for (info.ln = 522; info.ln <= 525; info.ln++) {
803 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
804 p = pack(p, line_buffer, elements);
810 /****************************************
812 ****************************************/
814 // start with first line numerber
815 active_video_line = 0;
817 if (info.fmt->lines_per_frame == 1125) {
819 elements = info.fmt->samples_per_line;
820 info.xyz = &FIELD_1_VERT_BLANKING;
821 for (info.ln = 1; info.ln <= 41; info.ln++) {
822 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
823 p = pack(p, line_buffer, elements);
826 elements = info.fmt->active_samples_per_line;
828 info.xyz = &FIELD_1_ACTIVE;
829 for (info.ln = 42; info.ln <= 1121; info.ln++) {
830 create_HD_SDI_Line(line_buffer, &info, active_video_line++, ACTIVE_VIDEO, vBuffer);
831 p = pack(p, line_buffer, elements);
834 info.xyz = &FIELD_1_VERT_BLANKING;
835 for (info.ln = 1122; info.ln <= 1125; info.ln++) {
836 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
837 p = pack(p, line_buffer, elements);
842 elements = info.fmt->samples_per_line;
843 info.xyz = &FIELD_1_VERT_BLANKING;
844 for (info.ln = 1; info.ln <= 25; info.ln++) {
845 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
846 p = pack(p, line_buffer, elements);
849 elements = info.fmt->active_samples_per_line;
851 info.xyz = &FIELD_1_ACTIVE;
852 for (info.ln = 26; info.ln <= 745; info.ln++) {
853 create_HD_SDI_Line(line_buffer, &info, active_video_line++, ACTIVE_VIDEO, vBuffer);
854 p = pack(p, line_buffer, elements);
857 info.xyz = &FIELD_1_VERT_BLANKING;
858 for (info.ln = 746; info.ln <= 750; info.ln++) {
859 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
860 p = pack(p, line_buffer, elements);
867 // sum of bytes that have already been written to file
869 // store actual written bytes per 'write()
870 int written_bytes = 0;
873 * WRITE BUFFER TO FILEHANDLE
875 // Write the complete frame to output
876 // The "while" is necessary because the sdi device file does not take the complete frame at once
878 while (bytes < sdi_frame_size) {
880 if ((written_bytes = write(fh_sdi_video, data + bytes, sdi_frame_size - bytes)) < 0) {
881 fprintf(stderr, "\nunable to write SDI video.\n");
884 bytes += written_bytes;
887 // Check for events of the SDI board
889 if (ioctl(fh_sdi_video, SDI_IOC_TXGETEVENTS, &val) < 0) {
890 // Maybe this is not an SDI device...
891 //fprintf(stderr, "SDI VIDEO output:");
892 //perror("unable to get the transmitter event flags");
894 if (val & SDI_EVENT_TX_BUFFER) {
895 printf("SDI VIDEO driver transmit buffer queue underrun "
899 if (val & SDI_EVENT_TX_FIFO) {
900 printf("SDI VIDEO onboard transmit FIFO underrun detected.\n");
903 if (val & SDI_EVENT_TX_DATA) {
904 printf("SDI VIDEO transmit data change detected.\n");
909 // if available write audio data
912 // count writen bytes
915 // set number of samples and cut by 1600 if NTSC (handle problem of real time encoding of NTSC frequencies)
916 size_t samples_total_per_track = audio_format->samples;
917 uint16_t sample_number = 0;
918 size_t channels_per_track_total = 2;
919 uint8_t stream_number = 0;
921 //printf("samples_total_per_track:%li\n", samples_total_per_track);
923 // to write blockwise 2 samples of one track we must claculate the number of bytes we want to write per write-session
924 // 2samples = 2x16Bit = 32Bit = 4Byte
925 // 2samples = 2x32Bit = 64Bit = 8Byte
926 // set total bytes per session
927 size_t bytes_total = 0;
928 bytes_total = audio_format->aformat == mlt_audio_s16 ? channels_per_track_total * sizeof(int16_t) : bytes_total;
929 bytes_total = audio_format->aformat == mlt_audio_s32 ? channels_per_track_total * sizeof(int32_t) : bytes_total;
931 // write all samples of all streams interleaved
933 * aBuffer[track0]+sample1
934 * aBuffer[track0]+sample2
935 * aBuffer[track1]+sample1
936 * aBuffer[track1]+sample2
937 * aBuffer[track.]+sample1
938 * aBuffer[track.]+sample2
940 * aBuffer[track0]+sample3
941 * aBuffer[track0]+sample4
942 * aBuffer[track1]+sample3
943 * aBuffer[track1]+sample4
944 * aBuffer[track.]+sample3
945 * aBuffer[track.]+sample4
947 * aBuffer[track0]+sample5
948 * aBuffer[track0]+sample6
949 * aBuffer[track1]+sample5
950 * aBuffer[track1]+sample6
951 * aBuffer[track.]+sample5
952 * aBuffer[track.]+sample6
954 int sum_written_bytes = 0;
955 int sum_written_bytes_a = 0;
956 int sum_written_bytes_b = 0;
958 // write all samples per track
959 while (sample_number < samples_total_per_track) {
964 * Because we have and write a fix number of audio streams to SDI board:
965 * we have a actual number of real audio tracks and a rest number of pseudo tracks
968 while (stream_number < audio_streams) {
970 // write for every stream n samples
971 // n = number of channels per stream
973 while (written_bytes < bytes_total) {
974 written_bytes += write(fh_sdi_audio, (uint8_t *) aBuffer[stream_number] + sample_number * bytes_total + written_bytes, bytes_total
977 sum_written_bytes += written_bytes;
978 sum_written_bytes_a += written_bytes;
983 // write pseudo tracks
984 // now fill rest of audio tracks(AES frames) with NULL or copy of first track
985 while (stream_number < audio_format->channels/2) {
987 // write for every stream n samples
988 // n = number of channels per stream
990 while (written_bytes < bytes_total) {
991 written_bytes += write(fh_sdi_audio, (uint8_t *) aBuffer[0] + sample_number * bytes_total + written_bytes, bytes_total - written_bytes);
993 sum_written_bytes += written_bytes;
994 sum_written_bytes_b += written_bytes;
1001 // Check for events of the SDI audio device
1003 if (ioctl(fh_sdi_audio, SDIAUDIO_IOC_TXGETEVENTS, &val) < 0) {
1004 //Maybe this is not an SDI device...
1005 // fprintf(stderr, "SDI AUDIO output:");
1006 // perror("unable to get the transmitter event flags");
1008 if (val & SDIAUDIO_EVENT_TX_BUFFER) {
1009 printf("SDI AUDIO driver transmit buffer queue underrun "
1012 if (val & SDIAUDIO_EVENT_TX_FIFO) {
1013 printf("SDI AUDIO onboard transmit FIFO underrun detected.\n");
1015 if (val & SDIAUDIO_EVENT_TX_DATA) {
1016 printf("SDI AUDIO transmit data change detected.\n");
1022 return getDBN(my_DBN);
1023 } // end sdimaster_playout()
1026 //****************************************************************************************
1027 //*************************** Create Line **********************************************
1028 //****************************************************************************************
1030 /** generate one SDI line
1031 * @param *buf: buffer to hold the line
1032 * @param field: size of the video Buffer
1033 * @param active: v-blank or active-video
1034 * @param *video_buffer: video buffer
1035 * @param *audio_buffer2: 1.audio buffer ch1-ch2
1036 * @param *audio_buffer1: 2.audio buffer ch2-ch3
1037 * @param line: linenumber
1038 * @param AudioGroupCounter: count written AudioGroup
1039 * @param AudioGroups2Write: number of samples to write
1040 * @param audio_streams: number of audio streams to integrate
1042 static inline int create_SD_SDI_Line(uint16_t *buf, const struct line_info *info, int field, int active, uint8_t *video_buffer,
1043 int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], int linenumber_sdiframe, int active_video_line, int my_DBN, int16_t AudioGroupCounter,
1044 int16_t AudioGroups2Write, int audio_streams) {
1046 // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2)
1047 // *************************************************************************
1048 // 625 lines: | EAV | ANC | SAV | [CbY1CrY2] |
1049 // *************************************************************************
1050 // 1728 SDI-words: | 4 | 280 | 4 | 720+360+360=1440 |
1051 // *************************************************************************
1053 // points to current position in line
1056 //#########################################################################################
1057 /* TRS Timing Reference Signal for EAV
1067 *p++ = info->xyz->eav;
1068 //#########################################################################################
1070 /* ANC Ancillary Data with AES
1072 * [ADF][ADF][ADF][DID][DBN][DC][UDW]...[UDW][CS]
1075 // write ANC Data and get number of samples are written
1076 // step with `p` += to the number of written samples
1078 //printf("audio_streams:%i\n",audio_streams);
1080 // 1 stream, Audio Group 1 with AES Frame 1 - 2
1081 if (audio_streams == 1) {
1082 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[0], AudioGroupCounter, AudioGroups2Write);
1084 // 2 streams, Audio Group 1 with AES Frame 1 - 2
1085 if (audio_streams == 2) {
1086 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1088 // 3 streams, Audio Group 2 with AES Frame 1 - 4
1089 if (audio_streams == 3) {
1090 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1091 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[2], AudioGroupCounter, AudioGroups2Write);
1093 // 4 streams, Audio Group 2 with AES Frame 1 - 4
1094 if (audio_streams == 4) {
1095 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1096 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1098 // 5 streams, Audio Group 3 with AES Frame 1 - 6
1099 if (audio_streams == 5) {
1100 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1101 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1102 p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[4], AudioGroupCounter, AudioGroups2Write);
1104 // 6 streams, Audio Group 3 with AES Frame 1 - 6
1105 if (audio_streams == 6) {
1106 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1107 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1108 p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write);
1110 // 7 streams, Audio Group 4 with AES Frame 1 - 7
1111 if (audio_streams == 7) {
1112 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1113 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1114 p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write);
1115 p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[6], AudioGroupCounter, AudioGroups2Write);
1117 // 8 streams, Audio Group 4 with AES Frame 1 - 7
1118 if (audio_streams == 8) {
1119 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1120 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1121 p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write);
1122 p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[7], AudioGroupCounter, AudioGroups2Write);
1125 // Fill ANC data in until the end (position(p) to `ANCILLARY_DATA_SAMPLES`)
1126 while (p < (buf + ANCILLARY_DATA_SAMPLES + 4)) {
1127 // video color: black
1131 //#########################################################################################
1132 // TRS Timing Reference Signal for SAV
1136 *p++ = info->xyz->sav;
1137 //#########################################################################################
1140 // Because we skip the first line of video, it can happen that we read too far in the buffer
1141 if (active_video_line >= info->fmt->active_lines_per_frame) {
1142 active_video_line = info->fmt->active_lines_per_frame - 1; // in SD PAL was set 575
1144 //Index of the start of the current line in the video_buffer
1145 int start_of_current_line = active_video_line * info->fmt->active_samples_per_line;
1147 // If VBlank then fill the line with 0x200 and 0x040 (total black)
1151 while (p < (buf + info->fmt->samples_per_line)) {
1158 // Insert the video into the line
1159 while (p < (buf + info->fmt->samples_per_line)) { // fill the rest of the line with active video
1161 // shift "<< 2" because 8 bit data in 10 bit word
1163 *p = video_buffer[start_of_current_line + ((p - 288) - buf) + 1] << 2; // Cb
1165 if (*(p - 1) < 0x040)
1166 *(p - 1) = 0x040; // check values
1167 if (*(p - 1) > 0x3c0)
1169 *p = video_buffer[start_of_current_line + ((p - 288) - buf) - 1] << 2; // Y1
1171 if (*(p - 1) < 0x040)
1173 if (*(p - 1) > 0x3ac)
1175 *p = video_buffer[start_of_current_line + ((p - 288) - buf) + 1] << 2; // Cr
1177 if (*(p - 1) < 0x040)
1179 if (*(p - 1) > 0x3c0)
1181 *p = video_buffer[start_of_current_line + ((p - 288) - buf) - 1] << 2; // Y2
1183 if (*(p - 1) < 0x040)
1185 if (*(p - 1) > 0x3ac)
1195 * create_HD_SDI_Line - generate one line
1196 * @buf: pointer to a buffer
1197 * @info: pointer to a line information structure
1198 * @active_video_line
1200 * @video_buffer: pattern
1202 * Returns a negative error code on failure and zero on success.
1204 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) {
1205 uint16_t *p = buf, *endp, ln;
1206 uint16_t samples = info->blanking ? info->fmt->samples_per_line : info->fmt->active_samples_per_line;
1208 if (active_video_line >= info->fmt->active_lines_per_frame) {
1209 active_video_line = info->fmt->active_lines_per_frame - 1;
1212 int start_of_current_line = active_video_line * info->fmt->active_samples_per_line;
1214 if (info->blanking) {
1216 // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2)
1218 // *************************************************************************
1219 // 625 lines: | EAV | ANC | SAV | [CbY1CrY2] |
1220 // *************************************************************************
1221 // 1728 SDI-words: | 4 | 280 | 4 | 720+360+360=1440 |
1222 // *************************************************************************
1224 // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2)
1225 // Example HD 1080i:
1226 // *************************************************************************
1227 // 1125 lines: | EAV | LN | CRC | ANC | SAV | [CbY1CrY2] |
1228 // *************************************************************************
1229 // 5280 SDI-words: | 6 | 4 | 4 | 280 | 6 | 1920+720+720=3840 |
1230 // *************************************************************************
1232 if (info->fmt == &FMT_576i50) {
1237 *p++ = info->xyz->eav;
1246 *p++ = info->xyz->eav;
1247 *p++ = info->xyz->eav;
1249 ln = ((info->ln & 0x07f) << 2) | (~info->ln & 0x040) << 3;
1252 ln = ((info->ln & 0x780) >> 5) | 0x200;
1255 /* CRC, added by serializer */
1263 /* Horizontal blanking */
1264 while (p < (buf + info->fmt->samples_per_line - info->fmt->active_samples_per_line - 4)) {
1271 if (info->fmt == &FMT_576i50) {
1276 *p++ = info->xyz->sav;
1285 *p++ = info->xyz->sav;
1286 *p++ = info->xyz->sav;
1295 while (p < (buf + samples)) {
1306 while (p < (buf + samples)) {
1308 *p = video_buffer[start_of_current_line + (p - buf) + 1] << 2; // Cb
1310 //check values, this needs a lot of resources
1311 // if (*(p - 1) < 0x040)
1312 // *(p - 1) = 0x040;
1313 // if (*(p - 1) > 0x3c0)
1314 // *(p - 1) = 0x3c0;
1316 *p = video_buffer[start_of_current_line + (p - buf) - 1] << 2; // Y1
1318 // if (*(p - 1) < 0x040)
1319 // *(p - 1) = 0x040;
1320 // if (*(p - 1) > 0x3ac)
1321 // *(p - 1) = 0x3ac;
1323 *p = video_buffer[start_of_current_line + (p - buf) + 1] << 2; // Cr
1325 // if (*(p - 1) < 0x040)
1326 // *(p - 1) = 0x040;
1327 // if (*(p - 1) > 0x3c0)
1328 // *(p - 1) = 0x3c0;
1330 *p = video_buffer[start_of_current_line + (p - buf) - 1] << 2; // Y2
1332 // if (*(p - 1) < 0x040)
1333 // *(p - 1) = 0x040;
1334 // if (*(p - 1) > 0x3ac)
1335 // *(p - 1) = 0x3ac;
1343 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,
1344 int16_t AudioGroups2Write) {
1347 * ANC Ancillary Data (vgl. SMPTE 291-M page 6 )
1348 * [ADF][ADF][ADF][DID][DBN][DC][UDW]...[UDW][CS]
1352 // save only current position for return value
1354 // 16bit buffer to write temporarily 10bit word
1355 uint16_t buffer = 0; // set all explicit to zero, special the bit9 for parity
1357 int8_t parity_counter = 0;
1359 if (AudioGroups2Write > 0) {
1361 // 3 ADF (Ancillary Data Flag)
1366 // 1 DID (Data Identification)
1367 // save DID for checker()
1368 uint16_t *DID_pointer = p;
1369 *p++ = DID;// (AES Audio Data, Group
1370 // *p++ = 0x2FF; // (AES Audio Data, Group1=0x2FF)
1371 // *p++ = 0x1FD; // (AES Audio Data, Group2=0x1FD)
1372 // *p++ = 0x1FB; // (AES Audio Data, Group3=0x1FB)
1373 // *p++ = 0x2F9; // (AES Audio Data, Group4=0x2F9)
1375 // 1 DBN (Data Block Number) inactiv: 1000000000 b9,b8,b7-b0 ; SMPTE 272-M chapter15.1
1378 // 1 DBN (dynamic version0.1-beta ), should start with previus DBN of SDI-Frame
1379 // -need "previus DBN" or "current framenumber"
1381 // [1] [1] << start sdi frame
1392 // [625] [115] << end sdi frame
1393 // [1] [116] << start sdi frame
1394 // Accuracy of videoline_sdiframe(1 up to 625) to 8bit (1-255)
1395 //buffer = ((videoline_sdiframe-1) % 255)+1;
1398 // count binary ones for parity
1400 for (i = 0; i < 8; i++) {
1401 if (buffer & (1 << i))
1404 if ((parity_counter % 2) == 0) { //else leave the 0
1405 buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1407 buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1411 // 1 DC (Data Counter)
1412 // number of UDW = AudioGroups2Write x 2AESFrames x 2channesl x 3words(X,X+1,X+2)
1413 buffer = AudioGroups2Write * 2* 2* 3 ; parity_counter= 0;
1414 // count binary ones for parity
1415 for (i=0; i<8; i++) {
1416 if (buffer & (1 << i))
1419 if ((parity_counter%2)==0) { //else leave the 0
1420 buffer+= 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1422 buffer+= 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1426 int16_t sample_number=0;
1427 int16_t counter = 0;
1429 // = n x 1 AudioGroup
1430 // = n x 2 x 1AESFrame
1431 // = n x 2 x 2samples
1434 while (counter < AudioGroups2Write*2) { /* 4:3 */
1436 // write one Audio Group with 4 x AES subframes
1437 // ( samples for ch01,ch02,ch03,ch04 or ch05,ch06,ch07,ch08 or ch09,ch10,ch11,ch12 or ch13,ch14,ch15,ch16)
1438 // and use audio_buffer_A(stereo) and audio_buffer_B(stereo)
1439 // `pack_AES_subframe()` write 3 ANC words (3*10bit), also 1 sample
1441 sample_number=(AudioGroupCounter*2)+ counter;
1442 pack_AES_subframe(p, getChannelStatusBit(sample_number/2, 1),
1443 getZBit(sample_number/2), 0, &audio_buffer_A[sample_number]); // left
1444 p+=3; // step 3 words
1446 sample_number=(AudioGroupCounter*2)+ counter+1;
1447 pack_AES_subframe(p, getChannelStatusBit(sample_number/2, 2),
1448 getZBit(sample_number/2), 1, &audio_buffer_A[sample_number]); // right
1451 sample_number=(AudioGroupCounter*2)+ counter;
1452 pack_AES_subframe(p, getChannelStatusBit(sample_number/2, 3),
1453 getZBit(sample_number/2), 2, &audio_buffer_B[sample_number]); // left
1456 sample_number=(AudioGroupCounter*2)+ counter+1;
1457 pack_AES_subframe(p, getChannelStatusBit(sample_number/2, 4),
1458 getZBit(sample_number/2), 3, &audio_buffer_B[sample_number]); // right
1463 // 1 CS (Checksum from DID - UDW)
1464 *p++ = checker(DID_pointer);
1466 // fill ANC with one dummy for videocolor black
1467 // rest until end of `ANCILLARY_DATA_SAMPLES` will be fill in a loop after call this function
1473 // calculate checksumm of ANC (SMPTE 272-M 15.3 Checksum (CS))
1474 static uint16_t checker(uint16_t *DID_pointer) {
1479 // DID - Datablock Identification
1480 cs += (*DID_pointer++) & 0x1FF; // 9 x LSB
1482 // DBN - Datablock Number
1483 cs += (*DID_pointer++) & 0x1FF; // 9 x LSB
1486 cs += (*DID_pointer) & 0x1FF; // 9 x LSB
1488 // store address of DC an ad to the real value of DC
1489 // DataCounter store
1490 // ´ende´ point to DataCounter
1491 uint16_t *ende = DID_pointer;
1492 // ´ende´ point to last field
1493 ende += (*DID_pointer) & 0xFF; // without parity-Bit and ¬9-Bit
1497 // while DID_pointer point to smaller addres like 'ende'
1498 while (DID_pointer <= ende) {
1499 cs += (*DID_pointer++) & 0x1FF; // 9 x LSB
1502 // limit to 9Bit, because of overflow of sum
1505 // set bit10 NOT bit9:
1507 // - & with bitmask '01 0000 0000'
1508 // - shift rest (1xbit)to left
1510 cs += ((~cs) & 0x100) << 1;
1517 * pack 16bit in AES subframe with 3 words (30 bit) and write in ´*p´
1518 * 10bit-words --> [X],[X+1], [X+2] implements 20bit for audio
1520 * BIT 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
1521 * ##### ### ### ### ### ### ### ### ### ###
1522 * [X] : [ !bit8, a5, a4, a3, a2, a1, a0, ch0, ch1, z ],
1523 * [X+1] : [ !bit8, a14, a13, a12, a11, a10, a9, a8, a7 , a6 ],
1524 * [X+2] : [ !bit8, P, C, U, V, a19, a18, a17, a16, a15 ]
1526 * @param *p: Pointer to SDI frame buffer
1527 * @param c: value of AES subframe Channel Status Bit
1528 * @param z: value of AES subframe
1529 * @param ch: channel od AES subframe (value:0,1,2,3)
1530 * @param *audio_samplex: pointer to the audio buffer
1532 static int pack_AES_subframe(uint16_t *p, int8_t c, int8_t z, int8_t ch, int16_t *audio_samplex) {
1535 * NOTE: WE JUST SUPPORT ONLY 16BIT SAMPLE SIZE
1538 // push 16bit up to 20bit(32bit)
1539 int32_t audio_sample = *audio_samplex;
1540 audio_sample = audio_sample << 4; // Shift by 4 (louder)
1543 int8_t parity_counter = 0;
1545 // 16bit buffer to write 10bit of [X]word,[X+1]word,[X+2]word,
1546 uint16_t buffer = 0;
1548 //#########################################################
1549 //### WORD X ############################################
1550 //#########################################################
1551 // word X: !bit8, a5, a4, a3, a2, a1, a0, ch1, ch0, z
1553 buffer = z; // z bit every 192bit = 1
1554 buffer += ch << 1; // ch1 - ch0
1555 buffer += (audio_sample & 0x3f) << 3; // a5 - a0
1556 buffer += ((~buffer) & 0x100) << 1; // !bit8
1563 for (i = 0; i < 9; i++) {
1564 if (buffer & 1 << i)
1568 //#########################################################
1569 //### WORD X+1 ############################################
1570 //#########################################################
1571 // word X+1: !bit8, a14, a13, a12, a11, a10, a9, a8, a7, a6
1574 buffer += (audio_sample >> 6) & 0x1ff; // a14 - a6
1575 buffer += ((~buffer) & 0x100) << 1; // !bit8
1580 // count ones (zähle Einsen)
1582 for (i = 0; i < 9; i++) {
1583 if (buffer & 1 << i)
1587 //#########################################################
1588 //### WORD X+2 ############################################
1589 //#########################################################
1590 // word X+2: !bit8, P, C, U, V, a19, a18, a17, a16, a15
1593 buffer += (audio_sample >> 15) & 0x01F; // a15 - a19
1594 // default of [V][U][C] bits = `0`
1595 //buffer += 1<<5; // V (AES sample validity bit)
1596 //buffer += 1<<6; // U (AES user bit)
1597 //buffer += 1<<7; // C (AES audio channel status bit)
1598 buffer += c << 7; // C (AES audio channel status bit)
1600 // count ones (zähle Einsen)
1601 for (i = 0; i < 8; i++) {
1602 if (buffer & 1 << i)
1606 // if (!parity_counter%2) //else leave the 0
1607 // buffer+= 1 << 8; // P (AES even parity bit)
1609 // buffer += ((~buffer) & 0x100 )<<1; // !bit8
1610 if ((parity_counter % 2) == 0) { //else leave the 0
1611 buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1613 buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1623 static uint8_t getZBit(int sample_number) {
1625 // start in SDI line 6 also 18samples later
1626 //sample_number+=192-18;
1628 if (sample_number % 192 == 0) {
1629 //printf("1 %i\n", sample_number);
1637 static uint8_t getChannelStatusBit(uint16_t sample_number, uint8_t ch) {
1640 uint8_t AESChannelStatusBit = 0;
1642 // start in SDI line 6 also 18samples later
1643 //AESChannelStatusBit=((sample_number+192-18)%192);
1644 // interval in 192bit
1645 AESChannelStatusBit = sample_number % 192;
1647 // when mulichannelmode is true
1648 if (AESChannelStatusBitArray[31] == 1) {
1649 // set bits for channel
1650 if (AESChannelStatusBit == 30 && ch == 2)
1652 if (AESChannelStatusBit == 30 && ch == 4)
1654 if (AESChannelStatusBit == 29 && (ch == 4))
1656 if (AESChannelStatusBit == 29 && (ch == 3))
1659 return AESChannelStatusBitArray[AESChannelStatusBit];
1662 static int16_t getNumberOfAudioGroups2Write(int linenumber) {
1664 // `4:3_VTR`-distribution
1665 if (linenumber >= 11 && linenumber <= 95) {
1666 if ((linenumber - 11) % 14 == 0) {
1671 } else if (linenumber >= 108 && linenumber <= 220) {
1672 if ((linenumber - 10) % 14 == 0) {
1677 } else if (linenumber >= 233 && linenumber <= 345) {
1678 if ((linenumber - 9) % 14 == 0) {
1683 } else if (linenumber >= 358 && linenumber <= 470) {
1684 if ((linenumber - 8) % 14 == 0) {
1689 } else if (linenumber >= 483 && linenumber <= 595) {
1690 if ((linenumber - 7) % 14 == 0) {
1695 } else if (linenumber >= 608 && linenumber <= 622) {
1696 if ((linenumber - 6) % 14 == 0) {
1705 // // `4:3`-distribution
1706 // if(linenumber<=315){
1707 // if(linenumber>=6 && linenumber<=8){
1710 // if((linenumber+5)%10==0){
1716 // if(linenumber>=319 && linenumber<=321){
1719 // if((linenumber-8)%10==0){
1726 // // full-distribution
1727 // if(linenumber<=45){
1733 // // fullhalf-distribution
1734 // if (linenumber==625)
1737 // if (linenumber%14==0) {
1744 static uint8_t getDBN(int my_DBN) {
1746 return ((my_DBN - 1) % 255) + 1;
1750 * pack8 - pack a line of 8-bit data
1751 * @outbuf: pointer to the output buffer
1752 * @inbuf: pointer to the input buffer
1753 * @count: number of elements in the buffer
1755 * Returns a pointer to the next output location.
1757 static inline uint8_t *
1758 pack8(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
1759 uint16_t *inp = inbuf;
1760 uint8_t *outp = outbuf;
1762 while (inp < (inbuf + count)) {
1763 *outp++ = *inp++ >> 2;
1769 * pack10 - pack a line of 10-bit data
1770 * @outbuf: pointer to the output buffer
1771 * @inbuf: pointer to the input buffer
1772 * @count: number of elements in the buffer
1774 * Returns a pointer to the next output location.
1776 static inline uint8_t * pack10(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
1778 uint16_t *inp = inbuf;
1779 uint8_t *outp = outbuf;
1781 while (inp < (inbuf + count)) {
1782 *outp++ = *inp & 0xff;
1783 *outp = *inp++ >> 8;
1784 *outp++ += (*inp << 2) & 0xfc;
1785 *outp = *inp++ >> 6;
1786 *outp++ += (*inp << 4) & 0xf0;
1787 *outp = *inp++ >> 4;
1788 *outp++ += (*inp << 6) & 0xc0;
1789 *outp++ = *inp++ >> 2;
1795 * pack_v210 - pack a line of v210 data
1796 * @outbuf: pointer to the output buffer
1797 * @inbuf: pointer to the input buffer
1798 * @count: number of elements in the buffer
1800 * Returns a pointer to the next output location.
1802 static inline uint8_t * pack_v210(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
1804 uint16_t *inp = inbuf;
1805 uint8_t *outp = outbuf;
1807 count = (count / 96) * 96 + ((count % 96) ? 96 : 0);
1808 while (inp < (inbuf + count)) {
1809 *outp++ = *inp & 0xff;
1810 *outp = *inp++ >> 8;
1811 *outp++ += (*inp << 2) & 0xfc;
1812 *outp = *inp++ >> 6;
1813 *outp++ += (*inp << 4) & 0xf0;
1814 *outp++ = *inp++ >> 4;
1820 static int sdimaster_close() {
1826 close(fh_sdi_audio);
1828 close(fh_sdi_video);
1834 * mkline - generate one line
1835 * @buf: pointer to a buffer
1836 * @info: pointer to a line information structure
1839 * Returns a negative error code on failure and zero on success.
1841 static int mkline(unsigned short int *buf, const struct line_info *info, unsigned int pattern) {
1842 const unsigned int b = 205;
1843 unsigned short int *p = buf, *endp;
1844 unsigned int samples = info->blanking ? info->fmt->samples_per_line : info->fmt->active_samples_per_line;
1846 if (info->blanking) {
1851 *p++ = info->xyz->eav;
1852 /* Horizontal blanking */
1853 while (p < (buf + 272)) {
1863 *p++ = info->xyz->sav;
1870 while (p < (buf + samples)) {
1878 while (p < (buf + samples)) {
1935 while (p < (buf + samples)) {
1992 while (p < (buf + samples)) {
2032 /* blacker than black */
2048 /* whiter than black */
2057 while (p < (buf + samples)) {
2068 static int setSDIVideoProperties(enum sdi_setting_video_e setting, char * value, char * device) {
2070 const char fmt[] = "/sys/class/sdivideo/sdivideo%cx%i/%s";
2073 char type, name[256], data[256];
2076 /* Get the sysfs info */
2077 memset(&buf, 0, sizeof(buf));
2080 * Stat the file, fills the structure with info about the file
2081 * Get the major number from device node
2083 if (stat(device, &buf) < 0) {
2084 fprintf(stderr, "%s: ", device);
2085 perror("unable to get the file status");
2089 /* Check if it is a character device or not */
2090 if (!S_ISCHR (buf.st_mode)) {
2091 fprintf(stderr, "%s: not a character device\n", device);
2095 /* Check the minor number to determine if it is a receive or transmit device */
2096 type = (buf.st_rdev & 0x0080) ? 'r' : 't';
2098 /* Get the receiver or transmitter number */
2099 num = buf.st_rdev & 0x007f;
2101 /* Build the path to sysfs file */
2102 snprintf(name, sizeof(name), fmt, type, num, "dev");
2103 memset(data, 0, sizeof(data));
2105 /* Read sysfs file (dev) */
2106 if (util_read(name, data, sizeof(data)) < 0) {
2107 fprintf(stderr, "%s: ", device);
2108 perror("unable to get the device number");
2111 /* Compare the major number taken from sysfs file to the one taken from device node */
2112 if (strtoul(data, &endptr, 0) != (buf.st_rdev >> 8)) {
2113 fprintf(stderr, "%s: not a SMPTE 292M/SMPTE 259M-C device\n", device);
2116 if (*endptr != ':') {
2117 fprintf(stderr, "%s: error reading %s\n", device, name);
2121 // Which setting do we write
2122 if (setting == SETTING_BUFFER_NUMBER_VIDEO) {
2123 snprintf(name, sizeof(name), fmt, type, num, "buffers");
2124 snprintf(data, sizeof(data), "%s\n", value);
2125 if (util_write(name, data, sizeof(data)) < 0) {
2126 fprintf(stderr, "%s: ", device);
2127 perror("unable to set the number of buffers");
2130 printf("\tSet number of buffers = %s\n", value);
2131 } else if (setting == SETTING_BUFFER_SIZE_VIDEO) {
2132 snprintf(name, sizeof(name), fmt, type, num, "bufsize");
2133 snprintf(data, sizeof(data), "%s\n", value);
2134 if (util_write(name, data, sizeof(data)) < 0) {
2135 fprintf(stderr, "%s: ", device);
2136 perror("unable to set the buffer size");
2139 printf("\tSet buffer size = %s Bytes\n", value);
2140 } else if (setting == SETTING_CLOCK_SOURCE) {
2141 snprintf(name, sizeof(name), fmt, type, num, "clock_source");
2142 snprintf(data, sizeof(data), "%s\n", value);
2143 if (util_write(name, data, sizeof(data)) < 0) {
2144 fprintf(stderr, "%s: ", device);
2145 perror("unable to set the clock source");
2148 printf("\tSet clock source = %s\n", value);
2149 } else if (setting == SETTING_DATA_MODE) {
2150 snprintf(name, sizeof(name), fmt, type, num, "mode");
2151 snprintf(data, sizeof(data), "%s\n", value);
2152 if (util_write(name, data, sizeof(data)) < 0) {
2153 fprintf(stderr, "%s: ", device);
2154 perror("unable to set the interface operating mode");
2157 printf("\tSet data mode = %s\n", value);
2158 } else if (setting == SETTING_FRAME_MODE) {
2159 snprintf(name, sizeof(name), fmt, type, num, "frame_mode");
2160 snprintf(data, sizeof(data), "%s\n", value);
2161 if (util_write(name, data, sizeof(data)) < 0) {
2162 fprintf(stderr, "%s: ", device);
2163 perror("unable to set the interface frame mode");
2166 printf("\tSet frame mode = %s\n", value);
2173 static int setSDIAudioProperties(enum sdi_setting_audio_e setting, char * value, char * device) {
2174 const char fmt[] = "/sys/class/sdiaudio/sdiaudio%cx%i/%s";
2177 char type, name[256], data[256];
2180 /* Get the sysfs info */
2181 memset(&buf, 0, sizeof(buf));
2182 if (stat(device, &buf) < 0) {
2183 fprintf(stderr, "%s: ", device);
2184 perror("unable to get the file status");
2187 if (!S_ISCHR (buf.st_mode)) {
2188 fprintf(stderr, "%s: not a character device\n", device);
2191 type = (buf.st_rdev & 0x0080) ? 'r' : 't';
2192 num = buf.st_rdev & 0x007f;
2193 snprintf(name, sizeof(name), fmt, type, num, "dev");
2194 memset(data, 0, sizeof(data));
2195 if (util_read(name, data, sizeof(data)) < 0) {
2196 fprintf(stderr, "%s: ", device);
2197 perror("unable to get the device number");
2201 if (strtoul(data, &endptr, 0) != (buf.st_rdev >> 8)) {
2202 fprintf(stderr, "%s: not an audio device\n", device);
2205 if (*endptr != ':') {
2206 fprintf(stderr, "%s: error reading %s\n", device, name);
2210 if (setting == SETTING_BUFFER_NUMBER_AUDIO) {
2211 snprintf(name, sizeof(name), fmt, type, num, "buffers");
2212 snprintf(data, sizeof(data), "%s\n", value);
2214 if (util_write(name, data, sizeof(data)) < 0) {
2215 fprintf(stderr, "%s: ", device);
2216 perror("unable to set the number of buffers");
2219 printf("\tSet number of buffers = %s\n", value);
2220 } else if (setting == SETTING_BUFFER_SIZE_AUDIO) {
2221 snprintf(name, sizeof(name), fmt, type, num, "bufsize");
2222 snprintf(data, sizeof(data), "%s\n", value);
2223 if (util_write(name, data, sizeof(data)) < 0) {
2224 fprintf(stderr, "%s: ", device);
2225 perror("unable to set the buffer size");
2228 printf("\tSet buffer size = %s Bytes\n", value);
2229 } else if (setting == SETTING_SAMPLE_SIZE) {
2230 snprintf(name, sizeof(name), fmt, type, num, "sample_size");
2231 snprintf(data, sizeof(data), "%s\n", value);
2232 if (util_write(name, data, sizeof(data)) < 0) {
2233 fprintf(stderr, "%s: ", device);
2234 perror("unable to set the interface audio sample size");
2237 switch (atol(value)) {
2238 case SDIAUDIO_CTL_AUDSAMP_SZ_16:
2239 printf("\tAssuming 16-bit audio.\n");
2241 case SDIAUDIO_CTL_AUDSAMP_SZ_24:
2242 printf("\tAssuming 24-bit audio.\n");
2244 case SDIAUDIO_CTL_AUDSAMP_SZ_32:
2245 printf("\tAssuming 32-bit audio.\n");
2248 printf("\tSet audio sample size = %lu.\n", atol(value));
2251 } else if (setting == SETTING_SAMPEL_RATE) {
2252 snprintf(name, sizeof(name), fmt, type, num, "sample_rate");
2253 snprintf(data, sizeof(data), "%lu\n", atol(value));
2254 if (util_write(name, data, sizeof(data)) < 0) {
2255 fprintf(stderr, "%s: ", device);
2256 perror("unable to set the interface audio sample rate");
2259 switch (atoi(value)) {
2261 printf("\tAssuming 32 kHz audio.\n");
2264 printf("\tAssuming 44.1 kHz audio.\n");
2267 printf("\tAssuming 48 kHz audio.\n");
2270 printf("\tSet audio sample rate = %lu.\n", atol(value));
2273 } else if (setting == SETTING_CHANNELS) {
2274 snprintf(name, sizeof(name), fmt, type, num, "channels");
2275 snprintf(data, sizeof(data), "%lu\n", atol(value));
2276 if (util_write(name, data, sizeof(data)) < 0) {
2277 fprintf(stderr, "%s: ", device);
2278 perror("unable to set "
2279 "the interface audio channel enable");
2282 switch (atol(value)) {
2283 case SDIAUDIO_CTL_AUDCH_EN_0:
2284 printf("\tDisabling audio.\n");
2286 case SDIAUDIO_CTL_AUDCH_EN_2:
2287 printf("\tAssuming 2 channels of audio.\n");
2289 case SDIAUDIO_CTL_AUDCH_EN_4:
2290 printf("\tAssuming 4 channels of audio.\n");
2292 case SDIAUDIO_CTL_AUDCH_EN_6:
2293 printf("\tAssuming 6 channels of audio.\n");
2295 case SDIAUDIO_CTL_AUDCH_EN_8:
2296 printf("\tAssuming 8 channels of audio.\n");
2299 printf("\tSet audio channel enable = %lu.\n", atol(value));
2302 } else if (setting == SETTING_NON_AUDIO) {
2303 snprintf(name, sizeof(name), fmt, type, num, "non_audio");
2304 snprintf(data, sizeof(data), "0x%04lX\n", atol(value));
2305 if (util_write(name, data, sizeof(data)) < 0) {
2306 fprintf(stderr, "%s: ", device);
2307 perror("unable to set "
2308 "the interface non-audio");
2311 switch (atol(value)) {
2313 printf("\tPassing PCM audio.\n");
2316 printf("\tPassing non-audio.\n");
2319 printf("\tSet non-audio = 0x%04lX.\n", atol(value));
2327 static ssize_t util_read(const char *name, char *buf, size_t count) {
2330 if ((fd = open(name, O_RDONLY)) < 0) {
2333 ret = read(fd, buf, count);
2338 static ssize_t util_write(const char *name, const char *buf, size_t count) {
2341 if ((fd = open(name, O_WRONLY)) < 0) {
2344 ret = write(fd, buf, count);
2349 static char * itoa(uint64_t i) {
2354 char * mystring = (char *) malloc(50);
2355 sprintf(mystring, "%"PRIu64, i);