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 × 486/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 × 486/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,
135 const struct audio_format * audio_format) {
138 device_file_video = device_video;
139 device_file_audio = device_audio;
141 // set flag for using of blanking with ancillary data
142 info.blanking = blanking;
144 // set pack method for SDI word conversion
150 if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1
151 && myProfile->progressive == 0) {
152 info.fmt = &FMT_1080i60;
153 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080I_60HZ;
154 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den
155 == 1001 && myProfile->progressive == 0) {
156 info.fmt = &FMT_1080i5994;
157 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080I_59_94HZ;
158 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
159 && myProfile->progressive == 0) {
160 info.fmt = &FMT_1080i50;
161 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080I_50HZ;
162 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1
163 && myProfile->progressive == 1) {
164 info.fmt = &FMT_1080p30;
165 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_30HZ;
166 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den
167 == 1001 && myProfile->progressive == 1) {
168 info.fmt = &FMT_1080p2997;
169 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_29_97HZ;
170 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
171 && myProfile->progressive == 1) {
172 info.fmt = &FMT_1080p25;
173 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_25HZ;
174 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 24 && myProfile->frame_rate_den == 1
175 && myProfile->progressive == 1) {
176 info.fmt = &FMT_1080p24;
177 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_24HZ;
178 } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 24000 && myProfile->frame_rate_den
179 == 1001 && myProfile->progressive == 1) {
180 info.fmt = &FMT_1080p2398;
181 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_23_98HZ;
182 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 60 && myProfile->frame_rate_den == 1
183 && myProfile->progressive == 1) {
184 info.fmt = &FMT_720p60;
185 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_60HZ;
186 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 60000 && myProfile->frame_rate_den
187 == 1001 && myProfile->progressive == 1) {
188 info.fmt = &FMT_720p5994;
189 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_59_94HZ;
190 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 50 && myProfile->frame_rate_den == 1
191 && myProfile->progressive == 1) {
192 info.fmt = &FMT_720p50;
193 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_50HZ;
194 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1
195 && myProfile->progressive == 1) {
196 info.fmt = &FMT_720p30;
197 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_30HZ;
198 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den
199 == 1001 && myProfile->progressive == 1) {
200 info.fmt = &FMT_720p2997;
201 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_29_97HZ;
202 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
203 && myProfile->progressive == 1) {
204 info.fmt = &FMT_720p25;
205 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_25HZ;
206 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 24 && myProfile->frame_rate_den == 1
207 && myProfile->progressive == 1) {
208 info.fmt = &FMT_720p24;
209 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_24HZ;
210 } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 24000 && myProfile->frame_rate_den
211 == 1001 && myProfile->progressive == 1) {
212 info.fmt = &FMT_720p2398;
213 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_23_98HZ;
214 } else if (myProfile->width == 720 && myProfile->height == 576 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
215 && myProfile->progressive == 0) {
216 info.fmt = &FMT_576i50;
217 sdi_frame_mode = SDIVIDEO_CTL_BT_601_576I_50HZ;
218 } else if (myProfile->width == 720 && myProfile->height == 486 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den
219 == 1001 && myProfile->progressive == 0) {
220 info.fmt = &FMT_486i5994;
221 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_125M_486I_59_94HZ;
222 } else if (myProfile->width == 720 && myProfile->height == 480 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den
223 == 1001 && myProfile->progressive == 0) {
224 info.fmt = &FMT_480i5994;
225 sdi_frame_mode = SDIVIDEO_CTL_SMPTE_125M_486I_59_94HZ;
227 printf("Consumer got unknown format: %s", myProfile->description);
228 info.fmt = &FMT_576i50;
229 sdi_frame_mode = SDIVIDEO_CTL_BT_601_576I_50HZ;
232 printf("Consumer use format: %s\nProfile: %i %i %i %i %i\n", myProfile->description, myProfile->width, myProfile->height,
233 myProfile->frame_rate_num, myProfile->frame_rate_den, myProfile->progressive);
235 // Check if the format supports own blanking (note: model 193 supports currently only active video at the video device file)
236 if (info.blanking && info.fmt != &FMT_576i50) {
237 printf("SDI consumer doesn't support blanking(HANC) for the configured SD board and SDI format. Try argument: blanking=false\n");
241 // if we write our own HANC we need an AES channel status bit array
245 // http://www.sencore.com/newsletter/Nov05/DigAudioChannelStatusBits.htm
247 // http://www.sencore.com/uploads/files/DigAudioChannelStatusBits.pdf
249 // create empty AESChannelStatusBitArray
251 for (i = 0; i < sizeof(AESChannelStatusBitArray) / sizeof(AESChannelStatusBitArray[0]); i++)
252 AESChannelStatusBitArray[i] = 0;
255 * Professional Format - Channel Status Bits
258 AESChannelStatusBitArray[0] = 1; // professional format
260 AESChannelStatusBitArray[1] = 0; // PCM Format
262 AESChannelStatusBitArray[2] = 1; // Emphasis: [100] No Emphasis
263 AESChannelStatusBitArray[3] = 0; // ^
264 AESChannelStatusBitArray[4] = 0; // ^
266 AESChannelStatusBitArray[5] = 0; // locked
268 AESChannelStatusBitArray[6] = 0; // sample frequency Fs: [01]48kHz, [10]44kHz, [11]32kHz
269 AESChannelStatusBitArray[7] = 1; // ^
271 AESChannelStatusBitArray[8] = 0; // channel mode: [0000] not indicated, [0001]2channels, [0010]1channel mono, ...
272 AESChannelStatusBitArray[9] = 0; // ^
273 AESChannelStatusBitArray[10] = 0; // ^
274 AESChannelStatusBitArray[11] = 1; // ^
276 AESChannelStatusBitArray[19] = 0; // Encoded sample word length [100]20bits,
277 AESChannelStatusBitArray[20] = 0; //
278 AESChannelStatusBitArray[21] = 0; //
280 AESChannelStatusBitArray[24] = 0; //
281 AESChannelStatusBitArray[25] = 0; //
282 AESChannelStatusBitArray[26] = 0; //
283 AESChannelStatusBitArray[27] = 0; //
284 AESChannelStatusBitArray[28] = 0; //
285 AESChannelStatusBitArray[29] = 0; //
286 AESChannelStatusBitArray[30] = 0; //
287 AESChannelStatusBitArray[31] = 0; // Multi Channel Mode
288 ////// Byte 4-21 //////
289 //AESChannelStatusBitArray[32-179]= 0;
290 ////// Byte 22 //////
291 AESChannelStatusBitArray[180] = 0; // Reliability Flags
292 AESChannelStatusBitArray[181] = 1; // ^
293 AESChannelStatusBitArray[182] = 1; // ^
294 AESChannelStatusBitArray[183] = 1; // ^
295 ////// Byte 23 //////
296 AESChannelStatusBitArray[184] = 0; // Cyclic Redundancy Check
297 AESChannelStatusBitArray[185] = 1; // ^
298 AESChannelStatusBitArray[186] = 0; // ^
299 AESChannelStatusBitArray[187] = 0; // ^
300 AESChannelStatusBitArray[188] = 1; // ^
301 AESChannelStatusBitArray[189] = 0; // ^
302 AESChannelStatusBitArray[190] = 1; // ^
303 AESChannelStatusBitArray[191] = 1; // ^
306 // set buffer for one line of active video samples
307 line_buffer = (uint16_t*) calloc(info.fmt->samples_per_line, sizeof(uint16_t));
309 // calculate and set buffer for the complete SDI frame
310 if (info.fmt != &FMT_576i50 && info.fmt != &FMT_486i5994) {
312 if (pack == pack_v210) {
313 samples = (info.fmt->samples_per_line / 96 * 48) + ((info.fmt->samples_per_line % 96) ? 48 : 0);
314 sdi_frame_size = samples * info.fmt->lines_per_frame * 8 / 3;
316 sdi_frame_size = info.fmt->samples_per_line * info.fmt->lines_per_frame;
319 if (pack == pack_v210) {
320 samples = (info.fmt->active_samples_per_line / 96 * 48) + ((info.fmt->active_samples_per_line % 96) ? 48 : 0);
321 sdi_frame_size = samples * info.fmt->active_lines_per_frame * 8 / 3;
323 sdi_frame_size = info.fmt->active_samples_per_line * info.fmt->active_lines_per_frame;
328 if (pack == pack_v210) {
329 sdi_frame_size = info.fmt->samples_per_line * 4 / 3 * info.fmt->lines_per_frame;
330 } else if (pack == pack8) {
331 sdi_frame_size = info.fmt->samples_per_line * info.fmt->lines_per_frame;
333 sdi_frame_size = info.fmt->samples_per_line * 10 / 8 * info.fmt->lines_per_frame;
336 if (pack == pack_v210) {
337 sdi_frame_size = info.fmt->active_samples_per_line * 4 / 3 * info.fmt->active_lines_per_frame;
338 } else if (pack == pack8) {
339 sdi_frame_size = info.fmt->active_samples_per_line * info.fmt->active_lines_per_frame;
341 sdi_frame_size = info.fmt->active_samples_per_line * 10 / 8 * info.fmt->active_lines_per_frame;
346 // (*10/8 because we store (TOTAL_SAMPLES*TOTAL_LINES) words with 10 bit in this 8 bit array) )
347 if (info.fmt == &FMT_576i50 && info.blanking) {
348 sdi_frame_size = info.fmt->samples_per_line * 10 / 8 * info.fmt->lines_per_frame;
352 printf("SDI frame size: %li\n", sdi_frame_size);
354 printf("Frame size for active video: %li\n", sdi_frame_size);
358 * Setup HD-SDI Master device (vidport):
360 * if device_file_video available then
361 * if vidport available
364 * 1. open device file handler
366 * if device_file_audio available then
368 * 2. open device file handler
372 if (device_file_video != NULL) {
374 // If we use a Linsys HD board with active video (without blanking) setup the board for the used mode
375 if (strstr(device_file_video, "sdivideotx") != NULL && !info.blanking) {
380 value = itoa(sdi_frame_size);
381 setSDIVideoProperties(SETTING_BUFFER_SIZE_VIDEO, value, device_video);
385 value = itoa(sdi_frame_mode);
386 setSDIVideoProperties(SETTING_FRAME_MODE, value, device_video);
391 setSDIVideoProperties(SETTING_DATA_MODE, "0", device_video);
392 else if (pack == pack_v210)
393 setSDIVideoProperties(SETTING_DATA_MODE, "1", device_video);
396 // open file handle for SDI(video) output
397 if ((fh_sdi_video = open(device_file_video, O_WRONLY)) == -1) {
399 printf("\ncould not open video output destination: %s\n", device_file_video);
402 printf("SDI consumer uses video device file: %s\n", device_file_video);
404 // Check if we have to use a separate device file for audio
405 if (device_file_audio != NULL) {
407 // set settings for audio device file
408 if (strstr(device_file_audio, "sdiaudiotx") != NULL && !info.blanking) {
413 * prepare sample size
414 * MLT suports: 16bit, 32bit
415 * LINSYS SDI boards supports: 16bit, 24bit, 32bit
416 * we set 16bit as default
418 uint8_t sample_size = audio_format->aformat == mlt_audio_s32 ? 32 : 16;
421 // audio buffer per frame (Bytes) = sample rate / frame rate * ( sample size / 1Byte ) x channels
423 audio_format->sample_rate / (myProfile->frame_rate_num / myProfile->frame_rate_den) * sample_size / 8
424 * audio_format->channels);
425 setSDIAudioProperties(SETTING_BUFFER_SIZE_AUDIO, value, device_audio);
429 value = itoa(audio_format->channels);
430 setSDIAudioProperties(SETTING_CHANNELS, value, device_audio);
434 value = itoa(audio_format->sample_rate);
435 setSDIAudioProperties(SETTING_SAMPEL_RATE, value, device_audio);
439 value = itoa(sample_size);
440 setSDIAudioProperties(SETTING_SAMPLE_SIZE, value, device_audio);
444 // open file handle for audio output
445 if ((fh_sdi_audio = open(device_file_audio, O_WRONLY)) == -1) {
447 printf("\nCould not open audio output destination: %s\n", device_file_audio);
450 printf("SDI consumer uses audio device file: %s\n", device_file_audio);
455 // set buffer for the complete SDI frame
456 data = (uint8_t*) calloc(sdi_frame_size, sizeof(uint8_t));
462 * Writes video and audio to specified files in SDI format
463 * @param *vBuffer: Pointer to a video Buffer
465 * @param *audio_format: mlt audio_format
466 * @param audio_streams: number of audio streams which have content in aBuffer (available 0-8)
467 * @return current DBN (data block number of SDI frame)
469 static int sdi_playout(uint8_t *vBuffer, int16_t aBuffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], const struct audio_format * audio_format,
470 int audio_streams, int my_DBN) {
472 // Pointer to the start of data. This is used to fill data line by line
475 //*******************************************************************************************
476 //**************** Build the SDI frame line by line ****************************************
477 //*******************************************************************************************
480 * if SDI FMT_576i50 for card ASSY 145 or ASSY 159, with access to whole SDI frame buffer
481 * and device_file_audio must be NULL
482 * than we write own audio data,
484 * than HD for card ASSY 193
486 //if (info.fmt == &FMT_576i50 && device_file_audio == NULL && !strcmp(device_file_video, "/dev/sdivideotx0")) {
487 if (info.fmt == &FMT_576i50 && info.blanking) {
489 //counter for the lines
491 int16_t AudioGroupCounter = 0;
493 /*#####################################################*/
494 /*######## FIELD 1 #######################*/
495 /*#####################################################*/
497 info.xyz = &FIELD_1_VERT_BLANKING;
499 // line 1-22 VERTICAL_BLANKING:23 lines SAV 0x2ac EAV 0x2d8
500 for (i = 1; i <= 5; i++) {
501 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
502 getNumberOfAudioGroups2Write(i), audio_streams);
503 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
504 p = pack10(p, line_buffer, info.fmt->samples_per_line);
506 for (i = 6; i <= 8; i++) {
507 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
508 getNumberOfAudioGroups2Write(i), audio_streams);
509 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
510 p = pack10(p, line_buffer, info.fmt->samples_per_line);
512 for (i = 9; i <= 22; i++) {
513 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
514 getNumberOfAudioGroups2Write(i), audio_streams);
515 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
516 p = pack10(p, line_buffer, info.fmt->samples_per_line);
518 // line 23-310 ACTIVE: 287 lines SAV 0x200 EAV 0x274
519 info.xyz = &FIELD_1_ACTIVE;
520 int f1counter = 1; // only odd lines
521 for (i = 23; i <= 310; i++) {
522 create_SD_SDI_Line(line_buffer, &info, FIELD_1, ACTIVE_VIDEO, vBuffer, aBuffer, i, f1counter, getDBN(my_DBN++),
523 AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
524 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
525 p = pack10(p, line_buffer, info.fmt->samples_per_line);
529 // line 311-312 VERTICAL_BLANKING: 2 lines SAV 0x2ac EAV 0x2d8
530 info.xyz = &FIELD_1_VERT_BLANKING;
531 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
532 getNumberOfAudioGroups2Write(i), audio_streams);
533 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
534 p = pack10(p, line_buffer, info.fmt->samples_per_line);
535 create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
536 getNumberOfAudioGroups2Write(i), audio_streams);
537 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
538 p = pack10(p, line_buffer, info.fmt->samples_per_line);
540 /*#####################################################*/
541 /*######## FIELD 2 ########################*/
542 /*#####################################################*/
544 info.xyz = &FIELD_2_VERT_BLANKING;
546 // line 313-336 VERTICAL_BLANKING: 23 lines SAV 0x3b0 EAV 0x3c4
547 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
548 getNumberOfAudioGroups2Write(i), audio_streams);
549 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
550 p = pack10(p, line_buffer, info.fmt->samples_per_line);
552 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
553 getNumberOfAudioGroups2Write(i), audio_streams);
554 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
555 p = pack10(p, line_buffer, info.fmt->samples_per_line);
557 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
558 getNumberOfAudioGroups2Write(i), audio_streams);
559 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
560 p = pack10(p, line_buffer, info.fmt->samples_per_line);
562 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
563 getNumberOfAudioGroups2Write(i), audio_streams);
564 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
565 p = pack10(p, line_buffer, info.fmt->samples_per_line);
567 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
568 getNumberOfAudioGroups2Write(i), audio_streams);
569 AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
570 p = pack10(p, line_buffer, info.fmt->samples_per_line);
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 // `getAudioGroups2Write()`=0
578 for (i = 319; i <= 321; i++) {
579 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
580 getNumberOfAudioGroups2Write(i), audio_streams);
581 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
582 p = pack10(p, line_buffer, info.fmt->samples_per_line);
584 for (i = 322; i <= 335; i++) {
585 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
586 getNumberOfAudioGroups2Write(i), audio_streams);
587 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
588 p = pack10(p, line_buffer, info.fmt->samples_per_line);
590 // line 336-623 ACTIVE: 288 lines SAV 0x31c EAV 0x368
591 info.xyz = &FIELD_2_ACTIVE;
592 int f2counter = 2; // only even Lines
593 for (i = 336; i <= 623; i++) {
595 create_SD_SDI_Line(line_buffer, &info, FIELD_2, ACTIVE_VIDEO, vBuffer, aBuffer, i, f2counter, getDBN(my_DBN++),
596 AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
597 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
598 p = pack10(p, line_buffer, info.fmt->samples_per_line);
601 // line 624-625 VERTICAL_BLANKING: 2 lines SAV 0x3b0 EAV 0x3c4
602 info.xyz = &FIELD_2_VERT_BLANKING;
603 for (i = 624; i <= 625; i++) {
604 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
605 getNumberOfAudioGroups2Write(i), audio_streams);
606 AudioGroupCounter += getNumberOfAudioGroups2Write(i);
607 p = pack10(p, line_buffer, info.fmt->samples_per_line);
610 } else { // use HD board without blanking
612 // start with first even line
613 active_video_line = 1;
615 /* *****************************************
616 * *********** LINE DISTRIBUTION ***********
617 * *****************************************
619 * << decide form of scanning (interlaced || progressive) >>
621 * << decide lines per frame (1125 || 625 || 525) >>
622 * if(1125) 1080x1920 HD
624 * else if(625) 576x720 PAL
626 * else (525) 486x720 NTSC
629 * << decide resolution (1125 || 750) >>
630 * if(1125) 1080x1920 HD
632 * else(750) 720x1280 HD
638 if (info.fmt->interlaced) {
640 /****************************************
642 ****************************************/
644 if (info.fmt->lines_per_frame == 1125) {
647 elements = info.fmt->samples_per_line;
648 info.xyz = &FIELD_1_VERT_BLANKING;
649 for (info.ln = 1; info.ln <= 20; info.ln++) {
650 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
651 p = pack(p, line_buffer, elements);
654 elements = info.fmt->active_samples_per_line;
656 info.xyz = &FIELD_1_ACTIVE;
657 for (info.ln = 21; info.ln <= 560; info.ln++) {
658 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
659 p = pack(p, line_buffer, elements);
660 active_video_line += 2;
663 info.xyz = &FIELD_1_VERT_BLANKING;
664 for (info.ln = 561; info.ln <= 563; info.ln++) {
665 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
666 p = pack(p, line_buffer, elements);
668 info.xyz = &FIELD_2_VERT_BLANKING;
669 for (info.ln = 564; info.ln <= 583; info.ln++) {
670 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
671 p = pack(p, line_buffer, elements);
674 // start with first odd line
675 active_video_line = 2;
677 info.xyz = &FIELD_2_ACTIVE;
678 for (info.ln = 584; info.ln <= 1123; info.ln++) {
679 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
680 p = pack(p, line_buffer, elements);
681 active_video_line += 2;
684 info.xyz = &FIELD_2_VERT_BLANKING;
685 for (info.ln = 1124; info.ln <= 1125; info.ln++) {
686 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
687 p = pack(p, line_buffer, elements);
690 } else if (info.fmt->lines_per_frame == 625) {
692 elements = info.fmt->active_samples_per_line;
694 // start with first even line
695 active_video_line = 1;
698 * Generate an SDI PAL frame
701 info.xyz = &FIELD_1_VERT_BLANKING;
702 for (info.ln = 1; info.ln <= 22; info.ln++) {
703 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
704 p = pack(p, line_buffer, elements);
707 info.xyz = &FIELD_1_ACTIVE;
708 for (info.ln = 23; info.ln <= 310; info.ln++) {
709 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
710 p = pack(p, line_buffer, elements);
711 active_video_line += 2;
714 info.xyz = &FIELD_1_VERT_BLANKING;
715 for (info.ln = 311; info.ln <= 312; info.ln++) {
716 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
717 p = pack(p, line_buffer, elements);
719 info.xyz = &FIELD_2_VERT_BLANKING;
720 for (info.ln = 313; info.ln <= 335; info.ln++) {
721 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
722 p = pack(p, line_buffer, elements);
726 // start with first odd line
727 active_video_line = 2;
729 info.xyz = &FIELD_2_ACTIVE;
730 for (info.ln = 336; info.ln <= 623; info.ln++) {
731 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
732 p = pack(p, line_buffer, elements);
733 active_video_line += 2;
736 info.xyz = &FIELD_2_VERT_BLANKING;
737 for (info.ln = 624; info.ln <= 625; info.ln++) {
738 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
739 p = pack(p, line_buffer, elements);
742 } else if (info.fmt->lines_per_frame == 525) {
745 * Generate an SDI NTSC frame
748 * 16 lines VERT_BLANKING FIELD_1_VERT_BLANKING
749 * 1 lines VERT_BLANKING FIELD_1_ACTIVE
750 * 3 lines ACTIVE_VIDEO FIELD_1_ACTIVE (opt. video data)
751 * 240 lines ACTIVE_VIDEO FIELD_1_ACTIVE
752 * 2 lines VERT_BLANKING FIELD_1_VERT_BLANKING
754 * 8 lines VERT_BLANKING FIELD_2_VERT_BLANKING
755 * 9 lines VERT_BLANKING FIELD_2_VERT_BLANKING
756 * 3 lines ACTIVE_VIDEO FIELD_2_ACTIVE (opt. video data)
757 * 240 lines ACTIVE_VIDEO FIELD_2_ACTIVE
758 * 4 lines VERT_BLANKING FIELD_2_VERT_BLANKING
762 elements = info.fmt->active_samples_per_line;
764 active_video_line = 1;
767 info.xyz = &FIELD_1_VERT_BLANKING;
768 for (info.ln = 1; info.ln <= 15; info.ln++) {
769 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
770 p = pack(p, line_buffer, elements);
772 for (info.ln = 16; info.ln <= 16; info.ln++) {
773 info.xyz = &FIELD_1_ACTIVE;
774 mkline(line_buffer, &info, VERT_BLANKING);
775 p = pack(p, line_buffer, elements);
779 info.xyz = &FIELD_1_ACTIVE;
782 if (info.fmt == &FMT_480i5994) {
783 // 3 lines opt. video data
784 for (info.ln = 17; info.ln <= 19; info.ln++) {
785 mkline(line_buffer, &info, BLACK);
786 p = pack(p, line_buffer, elements);
789 for (info.ln = 20; info.ln <= 259; info.ln++) {
790 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
791 p = pack(p, line_buffer, elements);
792 active_video_line += 2;
796 for (info.ln = 17; info.ln <= 259; info.ln++) {
797 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
798 p = pack(p, line_buffer, elements);
799 active_video_line += 2;
803 // 2 lines vertical data
804 info.xyz = &FIELD_1_VERT_BLANKING;
805 for (info.ln = 260; info.ln <= 261; info.ln++) {
806 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
807 p = pack(p, line_buffer, elements);
809 // 8 lines vertical data
810 info.xyz = &FIELD_2_VERT_BLANKING;
811 for (info.ln = 262; info.ln <= 269; info.ln++) {
812 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
813 p = pack(p, line_buffer, elements);
816 for (info.ln = 270; info.ln <= 278; info.ln++) {
817 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
818 p = pack(p, line_buffer, elements);
823 active_video_line = 0;
826 if (info.fmt == &FMT_480i5994) {
827 // 3 lines opt. video data
828 info.xyz = &FIELD_2_ACTIVE;
829 for (info.ln = 279; info.ln <= 281; info.ln++) {
830 mkline(line_buffer, &info, BLACK);
831 p = pack(p, line_buffer, elements);
834 for (info.ln = 282; info.ln <= 521; info.ln++) {
835 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
836 p = pack(p, line_buffer, elements);
837 active_video_line += 2;
841 for (info.ln = 279; info.ln <= 521; info.ln++) {
842 create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
843 p = pack(p, line_buffer, elements);
844 active_video_line += 2;
847 // 4 lines vertical data
849 info.xyz = &FIELD_2_VERT_BLANKING;
850 for (info.ln = 522; info.ln <= 525; info.ln++) {
851 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
852 p = pack(p, line_buffer, elements);
858 /****************************************
860 ****************************************/
862 // start with first line numerber
863 active_video_line = 0;
865 if (info.fmt->lines_per_frame == 1125) {
867 elements = info.fmt->samples_per_line;
868 info.xyz = &FIELD_1_VERT_BLANKING;
869 for (info.ln = 1; info.ln <= 41; info.ln++) {
870 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
871 p = pack(p, line_buffer, elements);
874 elements = info.fmt->active_samples_per_line;
876 info.xyz = &FIELD_1_ACTIVE;
877 for (info.ln = 42; info.ln <= 1121; info.ln++) {
878 create_HD_SDI_Line(line_buffer, &info, active_video_line++, ACTIVE_VIDEO, vBuffer);
879 p = pack(p, line_buffer, elements);
882 info.xyz = &FIELD_1_VERT_BLANKING;
883 for (info.ln = 1122; info.ln <= 1125; info.ln++) {
884 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
885 p = pack(p, line_buffer, elements);
890 elements = info.fmt->samples_per_line;
891 info.xyz = &FIELD_1_VERT_BLANKING;
892 for (info.ln = 1; info.ln <= 25; info.ln++) {
893 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
894 p = pack(p, line_buffer, elements);
897 elements = info.fmt->active_samples_per_line;
899 info.xyz = &FIELD_1_ACTIVE;
900 for (info.ln = 26; info.ln <= 745; info.ln++) {
901 create_HD_SDI_Line(line_buffer, &info, active_video_line++, ACTIVE_VIDEO, vBuffer);
902 p = pack(p, line_buffer, elements);
905 info.xyz = &FIELD_1_VERT_BLANKING;
906 for (info.ln = 746; info.ln <= 750; info.ln++) {
907 create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
908 p = pack(p, line_buffer, elements);
915 // sum of bytes that have already been written to file
917 // store actual written bytes per 'write()
918 int written_bytes = 0;
921 * WRITE BUFFER TO FILEHANDLE
923 // Write the complete frame to output
924 // The "while" is necessary because the sdi device file does not take the complete frame at once
926 while (bytes < sdi_frame_size) {
928 if ((written_bytes = write(fh_sdi_video, data + bytes, sdi_frame_size - bytes)) < 0) {
929 fprintf(stderr, "\nunable to write SDI video.\n");
932 bytes += written_bytes;
935 // Check for events of the SDI board
937 if (ioctl(fh_sdi_video, SDI_IOC_TXGETEVENTS, &val) < 0) {
938 // Maybe this is not an SDI device...
939 //fprintf(stderr, "SDI VIDEO output:");
940 //perror("unable to get the transmitter event flags");
942 if (val & SDI_EVENT_TX_BUFFER) {
943 printf("SDI VIDEO driver transmit buffer queue underrun "
947 if (val & SDI_EVENT_TX_FIFO) {
948 printf("SDI VIDEO onboard transmit FIFO underrun detected.\n");
951 if (val & SDI_EVENT_TX_DATA) {
952 printf("SDI VIDEO transmit data change detected.\n");
957 // if available write audio data
960 // count writen bytes
963 // set number of samples and cut by 1600 if NTSC (handle problem of real time encoding of NTSC frequencies)
964 size_t samples_total_per_track = audio_format->samples;
965 uint16_t sample_number = 0;
966 size_t channels_per_track_total = 2;
967 uint8_t stream_number = 0;
969 //printf("samples_total_per_track:%li\n", samples_total_per_track);
971 // to write blockwise 2 samples of one track we must claculate the number of bytes we want to write per write-session
972 // 2samples = 2x16Bit = 32Bit = 4Byte
973 // 2samples = 2x32Bit = 64Bit = 8Byte
974 // set total bytes per session
975 size_t bytes_total = 0;
976 bytes_total = audio_format->aformat == mlt_audio_s16 ? channels_per_track_total * sizeof(int16_t) : bytes_total;
977 bytes_total = audio_format->aformat == mlt_audio_s32 ? channels_per_track_total * sizeof(int32_t) : bytes_total;
979 // write all samples of all streams interleaved
981 * aBuffer[track0]+sample1
982 * aBuffer[track0]+sample2
983 * aBuffer[track1]+sample1
984 * aBuffer[track1]+sample2
985 * aBuffer[track.]+sample1
986 * aBuffer[track.]+sample2
988 * aBuffer[track0]+sample3
989 * aBuffer[track0]+sample4
990 * aBuffer[track1]+sample3
991 * aBuffer[track1]+sample4
992 * aBuffer[track.]+sample3
993 * aBuffer[track.]+sample4
995 * aBuffer[track0]+sample5
996 * aBuffer[track0]+sample6
997 * aBuffer[track1]+sample5
998 * aBuffer[track1]+sample6
999 * aBuffer[track.]+sample5
1000 * aBuffer[track.]+sample6
1002 int sum_written_bytes = 0;
1003 int sum_written_bytes_a = 0;
1004 int sum_written_bytes_b = 0;
1006 // write all samples per track
1007 while (sample_number < samples_total_per_track) {
1012 * Because we have and write a fix number of audio streams to SDI board:
1013 * we have a actual number of real audio tracks and a rest number of pseudo tracks
1015 // write all streams
1016 while (stream_number < audio_streams) {
1018 // write for every stream n samples
1019 // n = number of channels per stream
1021 while (written_bytes < bytes_total) {
1022 written_bytes += write(fh_sdi_audio, (uint8_t *) aBuffer[stream_number] + sample_number * bytes_total + written_bytes,
1023 bytes_total - written_bytes);
1025 sum_written_bytes += written_bytes;
1026 sum_written_bytes_a += written_bytes;
1031 // write pseudo tracks
1032 // now fill rest of audio tracks(AES frames) with NULL or copy of first track
1033 while (stream_number < audio_format->channels / 2) {
1035 // write for every stream n samples
1036 // n = number of channels per stream
1038 while (written_bytes < bytes_total) {
1039 written_bytes += write(fh_sdi_audio, (uint8_t *) aBuffer[0] + sample_number * bytes_total + written_bytes,
1040 bytes_total - written_bytes);
1042 sum_written_bytes += written_bytes;
1043 sum_written_bytes_b += written_bytes;
1050 // Check for events of the SDI audio device
1052 if (ioctl(fh_sdi_audio, SDIAUDIO_IOC_TXGETEVENTS, &val) < 0) {
1053 //Maybe this is not an SDI device...
1054 // fprintf(stderr, "SDI AUDIO output:");
1055 // perror("unable to get the transmitter event flags");
1057 if (val & SDIAUDIO_EVENT_TX_BUFFER) {
1058 printf("SDI AUDIO driver transmit buffer queue underrun "
1061 if (val & SDIAUDIO_EVENT_TX_FIFO) {
1062 printf("SDI AUDIO onboard transmit FIFO underrun detected.\n");
1064 if (val & SDIAUDIO_EVENT_TX_DATA) {
1065 printf("SDI AUDIO transmit data change detected.\n");
1071 return getDBN(my_DBN);
1072 } // end sdimaster_playout()
1075 //****************************************************************************************
1076 //*************************** Create Line **********************************************
1077 //****************************************************************************************
1079 /** generate one SDI line
1080 * @param *buf: buffer to hold the line
1081 * @param field: size of the video Buffer
1082 * @param active: v-blank or active-video
1083 * @param *video_buffer: video buffer
1084 * @param *audio_buffer2: 1.audio buffer ch1-ch2
1085 * @param *audio_buffer1: 2.audio buffer ch2-ch3
1086 * @param line: linenumber
1087 * @param AudioGroupCounter: count written AudioGroup
1088 * @param AudioGroups2Write: number of samples to write
1089 * @param audio_streams: number of audio streams to integrate
1091 static inline int create_SD_SDI_Line(uint16_t *buf, const struct line_info *info, int field, int active, uint8_t *video_buffer,
1092 int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], int linenumber_sdiframe, int active_video_line, int my_DBN,
1093 int16_t AudioGroupCounter, int16_t AudioGroups2Write, int audio_streams) {
1095 // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2)
1096 // *************************************************************************
1097 // 625 lines: | EAV | ANC | SAV | [CbY1CrY2] |
1098 // *************************************************************************
1099 // 1728 SDI-words: | 4 | 280 | 4 | 720+360+360=1440 |
1100 // *************************************************************************
1102 // points to current position in line
1105 //#########################################################################################
1106 /* TRS Timing Reference Signal for EAV
1116 *p++ = info->xyz->eav;
1117 //#########################################################################################
1119 /* ANC Ancillary Data with AES
1121 * [ADF][ADF][ADF][DID][DBN][DC][UDW]...[UDW][CS]
1124 // write ANC Data and get number of samples are written
1125 // step with `p` += to the number of written samples
1127 //printf("audio_streams:%i\n",audio_streams);
1129 // 1 stream, Audio Group 1 with AES Frame 1 - 2
1130 if (audio_streams == 1) {
1131 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[0], AudioGroupCounter, AudioGroups2Write);
1133 // 2 streams, Audio Group 1 with AES Frame 1 - 2
1134 if (audio_streams == 2) {
1135 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1137 // 3 streams, Audio Group 2 with AES Frame 1 - 4
1138 if (audio_streams == 3) {
1139 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1140 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[2], AudioGroupCounter, AudioGroups2Write);
1142 // 4 streams, Audio Group 2 with AES Frame 1 - 4
1143 if (audio_streams == 4) {
1144 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1145 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1147 // 5 streams, Audio Group 3 with AES Frame 1 - 6
1148 if (audio_streams == 5) {
1149 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1150 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1151 p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[4], AudioGroupCounter, AudioGroups2Write);
1153 // 6 streams, Audio Group 3 with AES Frame 1 - 6
1154 if (audio_streams == 6) {
1155 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1156 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1157 p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write);
1159 // 7 streams, Audio Group 4 with AES Frame 1 - 7
1160 if (audio_streams == 7) {
1161 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1162 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1163 p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write);
1164 p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[6], AudioGroupCounter, AudioGroups2Write);
1166 // 8 streams, Audio Group 4 with AES Frame 1 - 7
1167 if (audio_streams == 8) {
1168 p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
1169 p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
1170 p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write);
1171 p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[7], AudioGroupCounter, AudioGroups2Write);
1174 // Fill ANC data in until the end (position(p) to `ANCILLARY_DATA_SAMPLES`)
1175 while (p < (buf + ANCILLARY_DATA_SAMPLES + 4)) {
1176 // video color: black
1180 //#########################################################################################
1181 // TRS Timing Reference Signal for SAV
1185 *p++ = info->xyz->sav;
1186 //#########################################################################################
1189 // Because we skip the first line of video, it can happen that we read too far in the buffer
1190 if (active_video_line >= info->fmt->active_lines_per_frame) {
1191 active_video_line = info->fmt->active_lines_per_frame - 1; // in SD PAL was set 575
1193 //Index of the start of the current line in the video_buffer
1194 int start_of_current_line = active_video_line * info->fmt->active_samples_per_line;
1196 // If VBlank then fill the line with 0x200 and 0x040 (total black)
1200 while (p < (buf + info->fmt->samples_per_line)) {
1207 // Insert the video into the line
1208 while (p < (buf + info->fmt->samples_per_line)) { // fill the rest of the line with active video
1210 // shift "<< 2" because 8 bit data in 10 bit word
1212 *p = video_buffer[start_of_current_line + ((p - 288) - buf) + 1] << 2; // Cb
1214 if (*(p - 1) < 0x040)
1215 *(p - 1) = 0x040; // check values
1216 if (*(p - 1) > 0x3c0)
1218 *p = video_buffer[start_of_current_line + ((p - 288) - buf) - 1] << 2; // Y1
1220 if (*(p - 1) < 0x040)
1222 if (*(p - 1) > 0x3ac)
1224 *p = video_buffer[start_of_current_line + ((p - 288) - buf) + 1] << 2; // Cr
1226 if (*(p - 1) < 0x040)
1228 if (*(p - 1) > 0x3c0)
1230 *p = video_buffer[start_of_current_line + ((p - 288) - buf) - 1] << 2; // Y2
1232 if (*(p - 1) < 0x040)
1234 if (*(p - 1) > 0x3ac)
1244 * create_HD_SDI_Line - generate one line
1245 * @buf: pointer to a buffer
1246 * @info: pointer to a line information structure
1247 * @active_video_line
1249 * @video_buffer: pattern
1251 * Returns a negative error code on failure and zero on success.
1253 static inline int create_HD_SDI_Line(uint16_t *buf, const struct line_info *info, uint16_t active_video_line, unsigned int active,
1254 uint8_t *video_buffer) {
1255 uint16_t *p = buf, *endp, ln;
1256 uint16_t samples = info->blanking ? info->fmt->samples_per_line : info->fmt->active_samples_per_line;
1258 if (active_video_line >= info->fmt->active_lines_per_frame) {
1259 active_video_line = info->fmt->active_lines_per_frame - 1;
1262 int start_of_current_line = active_video_line * info->fmt->active_samples_per_line;
1264 if (info->blanking) {
1266 // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2)
1268 // *************************************************************************
1269 // 625 lines: | EAV | ANC | SAV | [CbY1CrY2] |
1270 // *************************************************************************
1271 // 1728 SDI-words: | 4 | 280 | 4 | 720+360+360=1440 |
1272 // *************************************************************************
1274 // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2)
1275 // Example HD 1080i:
1276 // *************************************************************************
1277 // 1125 lines: | EAV | LN | CRC | ANC | SAV | [CbY1CrY2] |
1278 // *************************************************************************
1279 // 5280 SDI-words: | 6 | 4 | 4 | 280 | 6 | 1920+720+720=3840 |
1280 // *************************************************************************
1282 if (info->fmt == &FMT_576i50) {
1287 *p++ = info->xyz->eav;
1296 *p++ = info->xyz->eav;
1297 *p++ = info->xyz->eav;
1299 ln = ((info->ln & 0x07f) << 2) | (~info->ln & 0x040) << 3;
1302 ln = ((info->ln & 0x780) >> 5) | 0x200;
1305 /* CRC, added by serializer */
1313 /* Horizontal blanking */
1314 while (p < (buf + info->fmt->samples_per_line - info->fmt->active_samples_per_line - 4)) {
1321 if (info->fmt == &FMT_576i50) {
1326 *p++ = info->xyz->sav;
1335 *p++ = info->xyz->sav;
1336 *p++ = info->xyz->sav;
1345 while (p < (buf + samples)) {
1356 while (p < (buf + samples)) {
1358 *p = video_buffer[start_of_current_line + (p - buf) + 1] << 2; // Cb
1360 //check values, this needs a lot of resources
1361 // if (*(p - 1) < 0x040)
1362 // *(p - 1) = 0x040;
1363 // if (*(p - 1) > 0x3c0)
1364 // *(p - 1) = 0x3c0;
1366 *p = video_buffer[start_of_current_line + (p - buf) - 1] << 2; // Y1
1368 // if (*(p - 1) < 0x040)
1369 // *(p - 1) = 0x040;
1370 // if (*(p - 1) > 0x3ac)
1371 // *(p - 1) = 0x3ac;
1373 *p = video_buffer[start_of_current_line + (p - buf) + 1] << 2; // Cr
1375 // if (*(p - 1) < 0x040)
1376 // *(p - 1) = 0x040;
1377 // if (*(p - 1) > 0x3c0)
1378 // *(p - 1) = 0x3c0;
1380 *p = video_buffer[start_of_current_line + (p - buf) - 1] << 2; // Y2
1382 // if (*(p - 1) < 0x040)
1383 // *(p - 1) = 0x040;
1384 // if (*(p - 1) > 0x3ac)
1385 // *(p - 1) = 0x3ac;
1393 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,
1394 int16_t AudioGroupCounter, int16_t AudioGroups2Write) {
1397 * ANC Ancillary Data (vgl. SMPTE 291-M page 6 )
1398 * [ADF][ADF][ADF][DID][DBN][DC][UDW]...[UDW][CS]
1402 // save only current position for return value
1404 // 16bit buffer to write temporarily 10bit word
1405 uint16_t buffer = 0; // set all explicit to zero, special the bit9 for parity
1407 int8_t parity_counter = 0;
1409 if (AudioGroups2Write > 0) {
1411 // 3 ADF (Ancillary Data Flag)
1416 // 1 DID (Data Identification)
1417 // save DID for checker()
1418 uint16_t *DID_pointer = p;
1419 *p++ = DID;// (AES Audio Data, Group
1420 // *p++ = 0x2FF; // (AES Audio Data, Group1=0x2FF)
1421 // *p++ = 0x1FD; // (AES Audio Data, Group2=0x1FD)
1422 // *p++ = 0x1FB; // (AES Audio Data, Group3=0x1FB)
1423 // *p++ = 0x2F9; // (AES Audio Data, Group4=0x2F9)
1425 // 1 DBN (Data Block Number) inactiv: 1000000000 b9,b8,b7-b0 ; SMPTE 272-M chapter15.1
1428 // 1 DBN (dynamic version0.1-beta ), should start with previus DBN of SDI-Frame
1429 // -need "previus DBN" or "current framenumber"
1431 // [1] [1] << start sdi frame
1442 // [625] [115] << end sdi frame
1443 // [1] [116] << start sdi frame
1444 // Accuracy of videoline_sdiframe(1 up to 625) to 8bit (1-255)
1445 //buffer = ((videoline_sdiframe-1) % 255)+1;
1448 // count binary ones for parity
1450 for (i = 0; i < 8; i++) {
1451 if (buffer & (1 << i))
1454 if ((parity_counter % 2) == 0) { //else leave the 0
1455 buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1457 buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1461 // 1 DC (Data Counter)
1462 // number of UDW = AudioGroups2Write x 2AESFrames x 2channesl x 3words(X,X+1,X+2)
1463 buffer = AudioGroups2Write * 2 * 2 * 3;
1465 // count binary ones for parity
1466 for (i = 0; i < 8; i++) {
1467 if (buffer & (1 << i))
1470 if ((parity_counter % 2) == 0) { //else leave the 0
1471 buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1473 buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1477 int16_t sample_number = 0;
1478 int16_t counter = 0;
1480 // = n x 1 AudioGroup
1481 // = n x 2 x 1AESFrame
1482 // = n x 2 x 2samples
1485 while (counter < AudioGroups2Write * 2) { /* 4:3 */
1487 // write one Audio Group with 4 x AES subframes
1488 // ( samples for ch01,ch02,ch03,ch04 or ch05,ch06,ch07,ch08 or ch09,ch10,ch11,ch12 or ch13,ch14,ch15,ch16)
1489 // and use audio_buffer_A(stereo) and audio_buffer_B(stereo)
1490 // `pack_AES_subframe()` write 3 ANC words (3*10bit), also 1 sample
1492 sample_number = (AudioGroupCounter * 2) + counter;
1493 pack_AES_subframe(p, getChannelStatusBit(sample_number / 2, 1), getZBit(sample_number / 2), 0, &audio_buffer_A[sample_number]); // left
1494 p += 3; // step 3 words
1496 sample_number = (AudioGroupCounter * 2) + counter + 1;
1497 pack_AES_subframe(p, getChannelStatusBit(sample_number / 2, 2), getZBit(sample_number / 2), 1, &audio_buffer_A[sample_number]); // right
1500 sample_number = (AudioGroupCounter * 2) + counter;
1501 pack_AES_subframe(p, getChannelStatusBit(sample_number / 2, 3), getZBit(sample_number / 2), 2, &audio_buffer_B[sample_number]); // left
1504 sample_number = (AudioGroupCounter * 2) + counter + 1;
1505 pack_AES_subframe(p, getChannelStatusBit(sample_number / 2, 4), getZBit(sample_number / 2), 3, &audio_buffer_B[sample_number]); // right
1510 // 1 CS (Checksum from DID - UDW)
1511 *p++ = checker(DID_pointer);
1513 // fill ANC with one dummy for videocolor black
1514 // rest until end of `ANCILLARY_DATA_SAMPLES` will be fill in a loop after call this function
1520 // calculate checksumm of ANC (SMPTE 272-M 15.3 Checksum (CS))
1521 static uint16_t checker(uint16_t *DID_pointer) {
1526 // DID - Datablock Identification
1527 cs += (*DID_pointer++) & 0x1FF; // 9 x LSB
1529 // DBN - Datablock Number
1530 cs += (*DID_pointer++) & 0x1FF; // 9 x LSB
1533 cs += (*DID_pointer) & 0x1FF; // 9 x LSB
1535 // store address of DC an ad to the real value of DC
1536 // DataCounter store
1537 // ´ende´ point to DataCounter
1538 uint16_t *ende = DID_pointer;
1539 // ´ende´ point to last field
1540 ende += (*DID_pointer) & 0xFF; // without parity-Bit and ¬9-Bit
1544 // while DID_pointer point to smaller addres like 'ende'
1545 while (DID_pointer <= ende) {
1546 cs += (*DID_pointer++) & 0x1FF; // 9 x LSB
1549 // limit to 9Bit, because of overflow of sum
1552 // set bit10 NOT bit9:
1554 // - & with bitmask '01 0000 0000'
1555 // - shift rest (1xbit)to left
1557 cs += ((~cs) & 0x100) << 1;
1564 * pack 16bit in AES subframe with 3 words (30 bit) and write in ´*p´
1565 * 10bit-words --> [X],[X+1], [X+2] implements 20bit for audio
1567 * BIT 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
1568 * ##### ### ### ### ### ### ### ### ### ###
1569 * [X] : [ !bit8, a5, a4, a3, a2, a1, a0, ch0, ch1, z ],
1570 * [X+1] : [ !bit8, a14, a13, a12, a11, a10, a9, a8, a7 , a6 ],
1571 * [X+2] : [ !bit8, P, C, U, V, a19, a18, a17, a16, a15 ]
1573 * @param *p: Pointer to SDI frame buffer
1574 * @param c: value of AES subframe Channel Status Bit
1575 * @param z: value of AES subframe
1576 * @param ch: channel od AES subframe (value:0,1,2,3)
1577 * @param *audio_samplex: pointer to the audio buffer
1579 static int pack_AES_subframe(uint16_t *p, int8_t c, int8_t z, int8_t ch, int16_t *audio_samplex) {
1582 * NOTE: WE JUST SUPPORT ONLY 16BIT SAMPLE SIZE
1585 // push 16bit up to 20bit(32bit)
1586 int32_t audio_sample = *audio_samplex;
1587 audio_sample = audio_sample << 4; // Shift by 4 (louder)
1590 int8_t parity_counter = 0;
1592 // 16bit buffer to write 10bit of [X]word,[X+1]word,[X+2]word,
1593 uint16_t buffer = 0;
1595 //#########################################################
1596 //### WORD X ############################################
1597 //#########################################################
1598 // word X: !bit8, a5, a4, a3, a2, a1, a0, ch1, ch0, z
1600 buffer = z; // z bit every 192bit = 1
1601 buffer += ch << 1; // ch1 - ch0
1602 buffer += (audio_sample & 0x3f) << 3; // a5 - a0
1603 buffer += ((~buffer) & 0x100) << 1; // !bit8
1610 for (i = 0; i < 9; i++) {
1611 if (buffer & 1 << i)
1615 //#########################################################
1616 //### WORD X+1 ############################################
1617 //#########################################################
1618 // word X+1: !bit8, a14, a13, a12, a11, a10, a9, a8, a7, a6
1621 buffer += (audio_sample >> 6) & 0x1ff; // a14 - a6
1622 buffer += ((~buffer) & 0x100) << 1; // !bit8
1627 // count ones (zähle Einsen)
1629 for (i = 0; i < 9; i++) {
1630 if (buffer & 1 << i)
1634 //#########################################################
1635 //### WORD X+2 ############################################
1636 //#########################################################
1637 // word X+2: !bit8, P, C, U, V, a19, a18, a17, a16, a15
1640 buffer += (audio_sample >> 15) & 0x01F; // a15 - a19
1641 // default of [V][U][C] bits = `0`
1642 //buffer += 1<<5; // V (AES sample validity bit)
1643 //buffer += 1<<6; // U (AES user bit)
1644 //buffer += 1<<7; // C (AES audio channel status bit)
1645 buffer += c << 7; // C (AES audio channel status bit)
1647 // count ones (zähle Einsen)
1648 for (i = 0; i < 8; i++) {
1649 if (buffer & 1 << i)
1653 // if (!parity_counter%2) //else leave the 0
1654 // buffer+= 1 << 8; // P (AES even parity bit)
1656 // buffer += ((~buffer) & 0x100 )<<1; // !bit8
1657 if ((parity_counter % 2) == 0) { //else leave the 0
1658 buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1660 buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
1670 static uint8_t getZBit(int sample_number) {
1672 // start in SDI line 6 also 18samples later
1673 //sample_number+=192-18;
1675 if (sample_number % 192 == 0) {
1676 //printf("1 %i\n", sample_number);
1684 static uint8_t getChannelStatusBit(uint16_t sample_number, uint8_t ch) {
1687 uint8_t AESChannelStatusBit = 0;
1689 // start in SDI line 6 also 18samples later
1690 //AESChannelStatusBit=((sample_number+192-18)%192);
1691 // interval in 192bit
1692 AESChannelStatusBit = sample_number % 192;
1694 // when mulichannelmode is true
1695 if (AESChannelStatusBitArray[31] == 1) {
1696 // set bits for channel
1697 if (AESChannelStatusBit == 30 && ch == 2)
1699 if (AESChannelStatusBit == 30 && ch == 4)
1701 if (AESChannelStatusBit == 29 && (ch == 4))
1703 if (AESChannelStatusBit == 29 && (ch == 3))
1706 return AESChannelStatusBitArray[AESChannelStatusBit];
1709 static int16_t getNumberOfAudioGroups2Write(int linenumber) {
1711 // `4:3_VTR`-distribution
1712 if (linenumber >= 11 && linenumber <= 95) {
1713 if ((linenumber - 11) % 14 == 0) {
1718 } else if (linenumber >= 108 && linenumber <= 220) {
1719 if ((linenumber - 10) % 14 == 0) {
1724 } else if (linenumber >= 233 && linenumber <= 345) {
1725 if ((linenumber - 9) % 14 == 0) {
1730 } else if (linenumber >= 358 && linenumber <= 470) {
1731 if ((linenumber - 8) % 14 == 0) {
1736 } else if (linenumber >= 483 && linenumber <= 595) {
1737 if ((linenumber - 7) % 14 == 0) {
1742 } else if (linenumber >= 608 && linenumber <= 622) {
1743 if ((linenumber - 6) % 14 == 0) {
1752 // // `4:3`-distribution
1753 // if(linenumber<=315){
1754 // if(linenumber>=6 && linenumber<=8){
1757 // if((linenumber+5)%10==0){
1763 // if(linenumber>=319 && linenumber<=321){
1766 // if((linenumber-8)%10==0){
1773 // // full-distribution
1774 // if(linenumber<=45){
1780 // // fullhalf-distribution
1781 // if (linenumber==625)
1784 // if (linenumber%14==0) {
1791 static uint8_t getDBN(int my_DBN) {
1793 return ((my_DBN - 1) % 255) + 1;
1797 * pack8 - pack a line of 8-bit data
1798 * @outbuf: pointer to the output buffer
1799 * @inbuf: pointer to the input buffer
1800 * @count: number of elements in the buffer
1802 * Returns a pointer to the next output location.
1804 static inline uint8_t *
1805 pack8(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
1806 uint16_t *inp = inbuf;
1807 uint8_t *outp = outbuf;
1809 while (inp < (inbuf + count)) {
1810 *outp++ = *inp++ >> 2;
1816 * pack10 - pack a line of 10-bit data
1817 * @outbuf: pointer to the output buffer
1818 * @inbuf: pointer to the input buffer
1819 * @count: number of elements in the buffer
1821 * Returns a pointer to the next output location.
1823 static inline uint8_t * pack10(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
1825 uint16_t *inp = inbuf;
1826 uint8_t *outp = outbuf;
1828 while (inp < (inbuf + count)) {
1829 *outp++ = *inp & 0xff;
1830 *outp = *inp++ >> 8;
1831 *outp++ += (*inp << 2) & 0xfc;
1832 *outp = *inp++ >> 6;
1833 *outp++ += (*inp << 4) & 0xf0;
1834 *outp = *inp++ >> 4;
1835 *outp++ += (*inp << 6) & 0xc0;
1836 *outp++ = *inp++ >> 2;
1842 * pack_v210 - pack a line of v210 data
1843 * @outbuf: pointer to the output buffer
1844 * @inbuf: pointer to the input buffer
1845 * @count: number of elements in the buffer
1847 * Returns a pointer to the next output location.
1849 static inline uint8_t * pack_v210(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
1851 uint16_t *inp = inbuf;
1852 uint8_t *outp = outbuf;
1854 count = (count / 96) * 96 + ((count % 96) ? 96 : 0);
1855 while (inp < (inbuf + count)) {
1856 *outp++ = *inp & 0xff;
1857 *outp = *inp++ >> 8;
1858 *outp++ += (*inp << 2) & 0xfc;
1859 *outp = *inp++ >> 6;
1860 *outp++ += (*inp << 4) & 0xf0;
1861 *outp++ = *inp++ >> 4;
1867 static int sdimaster_close() {
1873 close(fh_sdi_audio);
1875 close(fh_sdi_video);
1881 * mkline - generate one line
1882 * @buf: pointer to a buffer
1883 * @info: pointer to a line information structure
1886 * Returns a negative error code on failure and zero on success.
1888 static int mkline(unsigned short int *buf, const struct line_info *info, unsigned int pattern) {
1889 const unsigned int b = 205;
1890 unsigned short int *p = buf, *endp;
1891 unsigned int samples = info->blanking ? info->fmt->samples_per_line : info->fmt->active_samples_per_line;
1893 if (info->blanking) {
1898 *p++ = info->xyz->eav;
1899 /* Horizontal blanking */
1900 while (p < (buf + 272)) {
1910 *p++ = info->xyz->sav;
1917 while (p < (buf + samples)) {
1924 case BLACK: /* black line (filler for FMT_480i5994 ) */
1925 while (p < (buf + samples)) {
1932 case GREEN: /* green line for test purpose */
1933 while (p < (buf + samples)) {
1990 while (p < (buf + samples)) {
2047 while (p < (buf + samples)) {
2087 /* blacker than black */
2103 /* whiter than black */
2112 while (p < (buf + samples)) {
2123 static int setSDIVideoProperties(enum sdi_setting_video_e setting, char * value, char * device) {
2125 const char fmt[] = "/sys/class/sdivideo/sdivideo%cx%i/%s";
2128 char type, name[256], data[256];
2131 /* Get the sysfs info */
2132 memset(&buf, 0, sizeof(buf));
2135 * Stat the file, fills the structure with info about the file
2136 * Get the major number from device node
2138 if (stat(device, &buf) < 0) {
2139 fprintf(stderr, "%s: ", device);
2140 perror("unable to get the file status");
2144 /* Check if it is a character device or not */
2145 if (!S_ISCHR (buf.st_mode)) {
2146 fprintf(stderr, "%s: not a character device\n", device);
2150 /* Check the minor number to determine if it is a receive or transmit device */
2151 type = (buf.st_rdev & 0x0080) ? 'r' : 't';
2153 /* Get the receiver or transmitter number */
2154 num = buf.st_rdev & 0x007f;
2156 /* Build the path to sysfs file */
2157 snprintf(name, sizeof(name), fmt, type, num, "dev");
2158 memset(data, 0, sizeof(data));
2160 /* Read sysfs file (dev) */
2161 if (util_read(name, data, sizeof(data)) < 0) {
2162 fprintf(stderr, "%s: ", device);
2163 perror("unable to get the device number");
2166 /* Compare the major number taken from sysfs file to the one taken from device node */
2167 if (strtoul(data, &endptr, 0) != (buf.st_rdev >> 8)) {
2168 fprintf(stderr, "%s: not a SMPTE 292M/SMPTE 259M-C device\n", device);
2171 if (*endptr != ':') {
2172 fprintf(stderr, "%s: error reading %s\n", device, name);
2176 // Which setting do we write
2177 if (setting == SETTING_BUFFER_NUMBER_VIDEO) {
2178 snprintf(name, sizeof(name), fmt, type, num, "buffers");
2179 snprintf(data, sizeof(data), "%s\n", value);
2180 if (util_write(name, data, sizeof(data)) < 0) {
2181 fprintf(stderr, "%s: ", device);
2182 perror("unable to set the number of buffers");
2185 printf("\tSet number of buffers = %s\n", value);
2186 } else if (setting == SETTING_BUFFER_SIZE_VIDEO) {
2187 snprintf(name, sizeof(name), fmt, type, num, "bufsize");
2188 snprintf(data, sizeof(data), "%s\n", value);
2189 if (util_write(name, data, sizeof(data)) < 0) {
2190 fprintf(stderr, "%s: ", device);
2191 perror("unable to set the buffer size");
2194 printf("\tSet buffer size = %s Bytes\n", value);
2195 } else if (setting == SETTING_CLOCK_SOURCE) {
2196 snprintf(name, sizeof(name), fmt, type, num, "clock_source");
2197 snprintf(data, sizeof(data), "%s\n", value);
2198 if (util_write(name, data, sizeof(data)) < 0) {
2199 fprintf(stderr, "%s: ", device);
2200 perror("unable to set the clock source");
2203 printf("\tSet clock source = %s\n", value);
2204 } else if (setting == SETTING_DATA_MODE) {
2205 snprintf(name, sizeof(name), fmt, type, num, "mode");
2206 snprintf(data, sizeof(data), "%s\n", value);
2207 if (util_write(name, data, sizeof(data)) < 0) {
2208 fprintf(stderr, "%s: ", device);
2209 perror("unable to set the interface operating mode");
2212 printf("\tSet data mode = %s\n", value);
2213 } else if (setting == SETTING_FRAME_MODE) {
2214 snprintf(name, sizeof(name), fmt, type, num, "frame_mode");
2215 snprintf(data, sizeof(data), "%s\n", value);
2216 if (util_write(name, data, sizeof(data)) < 0) {
2217 fprintf(stderr, "%s: ", device);
2218 perror("unable to set the interface frame mode");
2221 printf("\tSet frame mode = %s\n", value);
2228 static int setSDIAudioProperties(enum sdi_setting_audio_e setting, char * value, char * device) {
2229 const char fmt[] = "/sys/class/sdiaudio/sdiaudio%cx%i/%s";
2232 char type, name[256], data[256];
2235 /* Get the sysfs info */
2236 memset(&buf, 0, sizeof(buf));
2237 if (stat(device, &buf) < 0) {
2238 fprintf(stderr, "%s: ", device);
2239 perror("unable to get the file status");
2242 if (!S_ISCHR (buf.st_mode)) {
2243 fprintf(stderr, "%s: not a character device\n", device);
2246 type = (buf.st_rdev & 0x0080) ? 'r' : 't';
2247 num = buf.st_rdev & 0x007f;
2248 snprintf(name, sizeof(name), fmt, type, num, "dev");
2249 memset(data, 0, sizeof(data));
2250 if (util_read(name, data, sizeof(data)) < 0) {
2251 fprintf(stderr, "%s: ", device);
2252 perror("unable to get the device number");
2256 if (strtoul(data, &endptr, 0) != (buf.st_rdev >> 8)) {
2257 fprintf(stderr, "%s: not an audio device\n", device);
2260 if (*endptr != ':') {
2261 fprintf(stderr, "%s: error reading %s\n", device, name);
2265 if (setting == SETTING_BUFFER_NUMBER_AUDIO) {
2266 snprintf(name, sizeof(name), fmt, type, num, "buffers");
2267 snprintf(data, sizeof(data), "%s\n", value);
2269 if (util_write(name, data, sizeof(data)) < 0) {
2270 fprintf(stderr, "%s: ", device);
2271 perror("unable to set the number of buffers");
2274 printf("\tSet number of buffers = %s\n", value);
2275 } else if (setting == SETTING_BUFFER_SIZE_AUDIO) {
2276 snprintf(name, sizeof(name), fmt, type, num, "bufsize");
2277 snprintf(data, sizeof(data), "%s\n", value);
2278 if (util_write(name, data, sizeof(data)) < 0) {
2279 fprintf(stderr, "%s: ", device);
2280 perror("unable to set the buffer size");
2283 printf("\tSet buffer size = %s Bytes\n", value);
2284 } else if (setting == SETTING_SAMPLE_SIZE) {
2285 snprintf(name, sizeof(name), fmt, type, num, "sample_size");
2286 snprintf(data, sizeof(data), "%s\n", value);
2287 if (util_write(name, data, sizeof(data)) < 0) {
2288 fprintf(stderr, "%s: ", device);
2289 perror("unable to set the interface audio sample size");
2292 switch (atol(value)) {
2293 case SDIAUDIO_CTL_AUDSAMP_SZ_16:
2294 printf("\tAssuming 16-bit audio.\n");
2296 case SDIAUDIO_CTL_AUDSAMP_SZ_24:
2297 printf("\tAssuming 24-bit audio.\n");
2299 case SDIAUDIO_CTL_AUDSAMP_SZ_32:
2300 printf("\tAssuming 32-bit audio.\n");
2303 printf("\tSet audio sample size = %lu.\n", atol(value));
2306 } else if (setting == SETTING_SAMPEL_RATE) {
2307 snprintf(name, sizeof(name), fmt, type, num, "sample_rate");
2308 snprintf(data, sizeof(data), "%lu\n", atol(value));
2309 if (util_write(name, data, sizeof(data)) < 0) {
2310 fprintf(stderr, "%s: ", device);
2311 perror("unable to set the interface audio sample rate");
2314 switch (atoi(value)) {
2316 printf("\tAssuming 32 kHz audio.\n");
2319 printf("\tAssuming 44.1 kHz audio.\n");
2322 printf("\tAssuming 48 kHz audio.\n");
2325 printf("\tSet audio sample rate = %lu.\n", atol(value));
2328 } else if (setting == SETTING_CHANNELS) {
2329 snprintf(name, sizeof(name), fmt, type, num, "channels");
2330 snprintf(data, sizeof(data), "%lu\n", atol(value));
2331 if (util_write(name, data, sizeof(data)) < 0) {
2332 fprintf(stderr, "%s: ", device);
2333 perror("unable to set "
2334 "the interface audio channel enable");
2337 switch (atol(value)) {
2338 case SDIAUDIO_CTL_AUDCH_EN_0:
2339 printf("\tDisabling audio.\n");
2341 case SDIAUDIO_CTL_AUDCH_EN_2:
2342 printf("\tAssuming 2 channels of audio.\n");
2344 case SDIAUDIO_CTL_AUDCH_EN_4:
2345 printf("\tAssuming 4 channels of audio.\n");
2347 case SDIAUDIO_CTL_AUDCH_EN_6:
2348 printf("\tAssuming 6 channels of audio.\n");
2350 case SDIAUDIO_CTL_AUDCH_EN_8:
2351 printf("\tAssuming 8 channels of audio.\n");
2354 printf("\tSet audio channel enable = %lu.\n", atol(value));
2357 } else if (setting == SETTING_NON_AUDIO) {
2358 snprintf(name, sizeof(name), fmt, type, num, "non_audio");
2359 snprintf(data, sizeof(data), "0x%04lX\n", atol(value));
2360 if (util_write(name, data, sizeof(data)) < 0) {
2361 fprintf(stderr, "%s: ", device);
2362 perror("unable to set "
2363 "the interface non-audio");
2366 switch (atol(value)) {
2368 printf("\tPassing PCM audio.\n");
2371 printf("\tPassing non-audio.\n");
2374 printf("\tSet non-audio = 0x%04lX.\n", atol(value));
2382 static ssize_t util_read(const char *name, char *buf, size_t count) {
2385 if ((fd = open(name, O_RDONLY)) < 0) {
2388 ret = read(fd, buf, count);
2393 static ssize_t util_write(const char *name, const char *buf, size_t count) {
2396 if ((fd = open(name, O_WRONLY)) < 0) {
2399 ret = write(fd, buf, count);
2404 static char * itoa(uint64_t i) {
2409 char * mystring = (char *) malloc(50);
2410 sprintf(mystring, "%"PRIu64, i);