-/*
+/**
+ *
+ * MLT SDI Consumer:
+ * request video and audio data from MLT and generate an SDI stream
+ *
+ * Copyright (C) Broadcasting Center Europe S.A. http://www.bce.lu
+ * an RTL Group Company http://www.rtlgroup.com
+ * All rights reserved.
+ *
+ * E-mail: support_plasec@bce.lu
*
- * MLT SDI Consumer: request video and audio data from MLT and generate an SDI stream
- * Copyright (C) 2008 Broadcasting Center Europe S.A. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
- *
* DESCRIPTION:
* This software act as interface between the MLT Frameworkas as
- * MLT Consumer and the Linear Systems Ltd. SMPTE 259M-C boards.
+ * MLT Consumer and the Linear Systems Ltd. SMPTE 292M and SMPTE 259M-C boards.
*
* Linear Systems can be contacted at http://www.linsys.ca
*
- * ---------------------------------------------------------------
+ **********************************************************************************
* System : INTeL I686 64Bit
- * OS : Linux SuSE Kernel 2.6.27.23-0.1-default
- * Compiler: gcc (c++)
- * ---------------------------------------------------------------
- * Project : MLT SDI Consumer for SD
+ * OS : Linux SuSE Kernel 2.6.27.39-0.2-default
+ * Compiler: gcc 4.3.2 (c++)
+ **********************************************************************************
+ * Project : MLT SDI Consumer for SD and HD
* Started by : Thomas Kurpick, Dipl.Inf. (FH)
- * ---------------------------------------------------------------
- * This program writes an SDI stream to the SDI driver provided
- * device files. E.g. SDI device file:
- * /dev/sditx0 (SD)
- * /dev/sditx1 (SD)
- * /dev/sditx2 (SD)
- * /dev/sditx4 (SD)
+ **********************************************************************************
+ * Supported and tested boards for SD-SDI or HD-SDI Output:
+ * PCI SDI Master™ (model 107)
+ * PCIe SDI Master™ (model 159)
+ * PCIe LP SDI Master™ FD (model 145)
+ * PCIe LP SDI Master™ Quad/o (model 180)
+ * PCIe LP HD-SDI Master™ O (model 193)
*
- * Tested with:
- * SDI Master™ PCI
- * SDI Master™ PCIe
- * SDI Master™ FD PCIe LP
- * SDI Master™ Quad/o PCIe LP
+ * Note: PCIe LP HD-SDI Master™ O (model 193) is an VidPort model and supports an
+ * seperate video and audio interface. Device file:
+ * /dev/sdivideotx[] for active video data
+ * /dev/sdiaudiotx[] for pcm audio data
*
- */
-
-/*
- * consumer_SDIstream.c
- * Consumer for MLT Framework > 0.2.4 (release 0.2.4 does NOT work, profiles where not implemented)
+ * This mlt consumer use the following device files:
+ * /dev/sditx[] (SD-PAL) up to 8 x AES (8 x stereo / 16 audio channels)
+ * /dev/sdivideotx[] (HD)
+ * /dev/sdiaudiotx[] (HD) up to 4 x AES (4 x stereo / 8 audio channels)
+ *
+ *
+ **********************************************************************************
+ * Last modified by:
+ * Thomas Kurpick 08.Jan.2010
+ * and
+ * Dan Dennedy 10.Feb.2010
+ * Ver. 2.0
+ * See also Git commit log.
+ *
+ **********************************************************************************
+ *
+ * Consumer properties:
+ * 'dev_video'
+ * 'dev_audio'
+ * 'blanking'
+ * Only to monitor the SDI output a beta version of jpeg-writer is implemented.
+ * 'jpeg_files' a number for output interval
+ * 'save_jpegs' path for image
+ *
+ * EXAMPLE:
*
- * Example:
- * inigo video.dv -consumer linsys_sdi:/dev/sditx0 buffer=0;
- * melt video.dv -consumer linsys_sdi:/dev/sditx0 buffer=0;
+ * SDI boards with full frame stream (with blanking):
+ * melt video.dv -consumer sdi:/dev/sditx0
+ * melt video.dv -consumer sdi:/dev/sditx0 blanking=true
+ * melt video.dv -consumer sdi dev_video=/dev/sditx0 blanking=true
+ * melt video.dv audio_index=all -consumer sdi dev_video=/dev/sditx0 blanking=true
*
- */
+ * SDI boards without full frame stream (without blanking):
+ * melt -profile atsc_1080i_50 video.mpeg audio_index=1 -consumer sdi dev_video=/dev/sdivideotx0 dev_audio=/dev/sdiaudiotx0 blanking=false
+ * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_audio=/dev/sdiaudiotx0 blanking=false
+ * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_audio=/dev/sdiaudiotx0 blanking=false jpeg_files=25 save_jpegs=channel_04.jpg
+ *
+ *
+ * SDI output formats and MLT profiles:
+ * #####################################################################################################################################################
+ * ########## SMPTE 274M 1920 x 1080 Image Sample Structure ############################################################################################
+ * #####################################################################################################################################################
+ * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model)
+ * 4 1920 x 1080/60/I interlaced 30 HZ 4 x AES (8 channels) atsc_1080i_60 193
+ * 5 1920 x 1080/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080i_5994 193
+ * 6 1920 x 1080/50/I interlaced 25 HZ 4 x AES (8 channels) atsc_1080i_50 193
+ * 7 1920 x 1080/30/P progressive 30 HZ 4 x AES (8 channels) atsc_1080p_30 193
+ * 8 1920 x 1080/29.97/P progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080p_2997 193
+ * 9 1920 x 1080/25/P progressive 25 HZ 4 x AES (8 channels) atsc_1080p_25 193
+ * 10 1920 x 1080/24/P progressive 24 HZ 4 x AES (8 channels) atsc_1080p_24 193
+ * 11 1920 x 1080/23.98/P progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_1080p_2398 193
+ *
+ * #####################################################################################################################################################
+ * ########## SMPTE 296M 1280 × 720 Progressive Image Sample Structure #################################################################################
+ * #####################################################################################################################################################
+ * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model)
+ * 1 1280 × 720/60 progressive 60 HZ 4 x AES (8 channels) atsc_720p_60 193
+ * 2 1280 × 720/59.94 progressive 60000/1001 ~ 59.97 HZ 4 x AES (8 channels) atsc_720p_5994 193
+ * 3 1280 × 720/50 progressive 50 HZ 4 x AES (8 channels) atsc_720p_50 193
+ * 4 1280 × 720/30 progressive 30 HZ 4 x AES (8 channels) atsc_720p_30 193
+ * 5 1280 × 720/29.97 progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_720p_2997 193
+ * 6 1280 × 720/25 progressive 25 HZ 4 x AES (8 channels) atsc_720p_25 193
+ * 7 1280 × 720/24 progressive 24 HZ 4 x AES (8 channels) atsc_720p_24 193
+ * 8 1280 × 720/23.98 progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_720p_2398 193
+ *
+ * #####################################################################################################################################################
+ * ########## SMPTE 125M 486i 29.97Hz & BT.656 576i 25Hz ###############################################################################################
+ * #####################################################################################################################################################
+ * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model)
+ * SD PAL 720 × 576/50/I interlaced 25 HZ 8 x AES (16 channels) dv_pal 180,145,159,107
+ * SD PAL 720 × 576/50/I interlaced 25 HZ 4 x AES (8 channels) dv_pal 193
+ * 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
+ * SD NTSC 720 × 480/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) sdi_486i_5994 193
+ *
+ **/
-#include <framework/mlt_frame.h>
#include <framework/mlt_consumer.h>
+#include <framework/mlt_frame.h>
+#include <framework/mlt_profile.h>
#include <framework/mlt_log.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdint.h>
#include <unistd.h>
+#ifdef WITH_JPEG
+// for JPEG output
+#include <jpeglib.h>
+#endif
+
#include "sdi_generator.c"
+// alias for "struct consumer_SDIstream_s *" , now we can write "consumer_SDIstream". Makes it more readable...
typedef struct consumer_SDIstream_s *consumer_SDIstream;
struct consumer_SDIstream_s {
-
+ // Most of these values are set to their defaults by the parent consumer
struct mlt_consumer_s parent; // This is the basic Consumer from which we fetch our data
- char *path_destination_sdi; // Path for SDI output
+ mlt_image_format pix_fmt; // Must be mlt_image_yuv422 for SDI
+
+ int width;
+ int height;
+
+ struct audio_format audio_format;
+ /** device file:
+ * /dev/sditx0
+ * /dev/sdivideotx0
+ * /dev/sdiaudiotx0
+ **/
+ char *device_file_video; // Path for SDI output
+ char *device_file_audio; // Path for exlusive SDI audio output
+
+ /* write own HANC (ancillary data) is available for:
+ * SDI board ASSY 193 HD 'blanking=false'
+ * SDI board ASSY 180 SD quad 'blanking=true'
+ * SDI board ASSY 145 SD single 'blanking=true'
+ *
+ * 0=false, 1=true
+ *
+ * */
+ uint8_t blanking;
+
+ // our audio channel pair for this frame
int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES]; // The SDI audio channel pairs for this frame
-};
-/** Forward references to static functions.
- */
+ char *video_fmt_name; // 1080i25, 1080p25, 576i50, 480i2997, ...
+
+};
+/**
+ * Forward references to static functions.
+ **/
static int consumer_start(mlt_consumer this);
static int consumer_stop(mlt_consumer this);
static int consumer_is_stopped(mlt_consumer this);
static void consumer_close(mlt_consumer parent);
static void *consumer_thread(void *);
-//*****************************************************************************************************
-//*****************************************************************************************************
-//*******************************************SDI Master Consumer***************************************
-//*****************************************************************************************************
-//*****************************************************************************************************
+static void consumer_write_JPEG(char * path, uint8_t **vBuffer, mlt_profile myProfile);
+int convertYCBCRtoRGB(int y1, int cb, int cr, int y2, int * target_rgb);
+/*****************************************************************************************************
+ ****************************************** SDI Master Consumer **************************************
+ *****************************************************************************************************/
-/**
- * This is what will be called by the factory
+/** This is what will be called by the factory
* @param profile: profile name for consumer
* @param type: unused
* @param *id: unused
// If malloc and consumer init ok
if (this != NULL && mlt_consumer_init(&this->parent, this, profile) == 0) {
+
// Get the parent consumer object
mlt_consumer parent = &this->parent;
// Set output path for SDI, default is "/dev/sditx0"
if (arg == NULL) {
- this->path_destination_sdi = strdup("/dev/sditx0");
+ this->device_file_video = strdup("/dev/sditx0");
} else {
- this->path_destination_sdi = strdup(arg);
+ this->device_file_video = strdup(arg);
}
// Set up start/stop/terminated callbacks
parent->stop = consumer_stop;
parent->is_stopped = consumer_is_stopped;
- // Hardcode the audio sample rate to 48KHz for SDI
- mlt_properties_set_int(MLT_CONSUMER_PROPERTIES(parent), "frequency", 48000);
+ // Set explizit to zero or other value
+ int i, j;
+ for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
+ for (j = 0; j < MAX_AUDIO_SAMPLES; j++) {
+ this->audio_buffer[i][j] = j;
+ }
+ }
// Return the consumer produced
return parent;
* Start the consumer.
**/
static int consumer_start(mlt_consumer parent) {
+
// Get the properties
mlt_properties properties = mlt_consumer_properties(parent);
}
/**
- * Stop the consumer.
+ * Stop the consumer
**/
static int consumer_stop(mlt_consumer parent) {
// Check that we're running
if (mlt_properties_get_int(properties, "running")) {
+
// Get the threads
pthread_t *consumer_pthread = mlt_properties_get_data(properties, "consumer_pthread", NULL);
// Wait for termination
pthread_join(*consumer_pthread, NULL);
+
}
return 0;
}
/**
- * Determine if the consumer is stopped.
+ * Determine if the consumer is stopped
**/
static int consumer_is_stopped(mlt_consumer this) {
// Get the properties
* Threaded wrapper for pipe.
**/
static void *consumer_thread(void *arg) {
+
// Identify the arg
consumer_SDIstream this = arg;
mlt_consumer consumer = &this->parent;
// Convenience functionality (this is to stop melt/inigo after the end of a playout)
- int terminate_on_pause = mlt_properties_get_int(MLT_CONSUMER_PROPERTIES(consumer), "terminate_on_pause");
- int terminated = 0;
+ int terminate_on_pause = mlt_properties_get_int(MLT_CONSUMER_PROPERTIES( consumer ), "terminate_on_pause");
+ int terminated = 0; // save ony status
+
+ int save_jpegs = mlt_properties_get_int(MLT_CONSUMER_PROPERTIES( consumer ), "save_jpegs");
+ char * jpeg_folder = mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "jpeg_file");
+
+ // If no folder is specified, skip jpeg export
+ if (jpeg_folder == NULL) {
+ save_jpegs = 0;
+ }
+
+ if (save_jpegs > 0)
+ mlt_log_info(MLT_CONSUMER_SERVICE(consumer), "Saving a JPEG every %i frame.\n", save_jpegs);
+
+ int counter = 0; // each second we save a Jpeg
+
+ // set blanking flag; is not nessary we write no own blanking(HANC) for HD board ASSY 193
+ if (mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "blanking") != NULL) {
+ // set value
+ if (strcmp(strdup(mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "blanking")), "false")) {
+ this->blanking = 1;
+ } else if (strcmp(strdup(mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "blanking")), "true")) {
+ this->blanking = 0;
+ } else {
+ this->blanking = 1;
+ }
+ } else {
+ // set default value without HD board, also with blanking
+ this->blanking = 1;
+ }
+
+ // set properties (path) for device files
+ if (mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "dev_video") != NULL) {
+ this->device_file_video = strdup(mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "dev_video"));
+ }
+ if (mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "dev_audio") != NULL) {
+ if (this->blanking == 0) {
+ this->device_file_audio = strdup(mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "dev_audio"));
+ } else {
+ // if we write HANC we do not write further audio data
+ mlt_log_info(MLT_CONSUMER_SERVICE(consumer), "Audio device file is set but will not be used.\n");
+ }
+ }
// Define a frame pointer
mlt_frame frame;
- if (!sdimaster_init(this->path_destination_sdi, 0)) {
+ if (!sdi_init(this->device_file_video, this->device_file_audio, this->blanking, mlt_service_profile((mlt_service) consumer))) {
exit(0);
}
double fps = mlt_properties_get_double(MLT_CONSUMER_PROPERTIES(consumer), "fps");
unsigned int count = 0;
+ // Tell the framework how we want our audio and video
+ int frequency = 48000;
+ int channels = 0;
+ int samples = mlt_sample_calculator(fps, frequency, count++);
+
+ this->audio_format.aformat = mlt_audio_s16;
+ this->audio_format.channels = 0;
+ this->pix_fmt = mlt_image_yuv422;
+
+ uint8_t *video_buffer;
+ int16_t *audio_buffer_tmp; // the upstream audio buffer
+
// Loop until told not to
while (!consumer_is_stopped(consumer) && terminated == 0) { //
// Check for termination
if (terminate_on_pause && frame != NULL) {
- terminated = mlt_properties_get_double(MLT_FRAME_PROPERTIES(frame), "_speed") == 0.0;
+ terminated = mlt_properties_get_double(MLT_FRAME_PROPERTIES( frame ), "_speed") == 0.0;
if (terminated == 1) {
- mlt_log_info(MLT_CONSUMER_SERVICE(consumer), "End of playout reached, terminating\n");
- fflush(stdout);
+ mlt_log_verbose(MLT_CONSUMER_SERVICE(consumer), "\nEnd of playout reached, terminating\n");
consumer_stop(consumer);
}
}
// True if mlt_consumer_rt_frame(...) successful
if (mlt_properties_get_int(mlt_frame_properties(frame), "rendered") == 1) {
- mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer);
-
- // Tell the framework how we want our audio and video
- int width = mlt_properties_get_int(properties, "width");
- int height = mlt_properties_get_int(properties, "height");
- int frequency = 48000;
- int channels = 0;
- int samples = mlt_sample_calculator(fps, frequency, count++);
- mlt_image_format pix_fmt = mlt_image_yuv422;
- mlt_audio_format aformat = mlt_audio_s16;
- uint8_t *video_buffer;
- int16_t *audio_buffer_tmp; // the upstream audio buffer
// Get the video from this frame and save it to our video_buffer
- mlt_frame_get_image(frame, &video_buffer, &pix_fmt, &width, &height, 0);
+ mlt_frame_get_image(frame, &video_buffer, &this->pix_fmt, &this->width, &this->height, 1);
// Get the audio from this frame and save it to our audio_buffer
- mlt_frame_get_audio(frame, (void**) &audio_buffer_tmp, &aformat, &frequency, &channels, &samples);
- mlt_log_debug(MLT_CONSUMER_SERVICE(consumer), "channels: %i samples: %i\n", channels, samples);
-
- int out_channels = channels;
- if ( mlt_properties_get( properties, "force_channels" ) )
- out_channels = mlt_properties_get_int( properties, "force_channels" );
-
- // Tell the sdi_generator.c to playout our frame
- // 8 audio streams with 2 stereo channels are possible
+ mlt_frame_get_audio(frame, (void**) &audio_buffer_tmp, &this->audio_format.aformat, &frequency, &channels, &samples);
+
+ this->audio_format.sample_rate = frequency;
+ this->audio_format.samples = samples;
+
+ // TODO, current hard coded to all 8 channels, also we write 8 channels to the sdi board
+ // the Linys SDI board must be right configured with the same number of channels!!!
+ this->audio_format.channels = 8;
+ // this->audio_format.channels = channels; // take given number of channels
+
+ /* Tell the sdi_generator.c to playout our frame
+ * 8 AES (8 x stereo channels are possible, max. 16 channels) Linsys SD board model: 107, 159, 145, 180
+ * 4 AES (4 x stereo channels are possible, max. 8 channels) Linsys HD board model: 193
+ */
if (video_buffer) {
+
+ // provide mapping of audio channels
int i, j = 0;
int map_channels, map_start;
- for (i = 0; i < MAX_AUDIO_STREAMS && j < out_channels; i++) {
+ for (i = 0; i < MAX_AUDIO_STREAMS && j < channels; i++) {
char key[27];
int c;
map_channels = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), key);
sprintf(key, "meta.map.audio.%d.start", i);
map_start = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), key);
+
if (!map_channels)
map_channels = channels - j;
for (c = 0; c < map_channels && j < channels; c++, j++) {
}
}
}
- my_dbn = sdimaster_playout(video_buffer, this->audio_buffer, (out_channels + 1) / 2, my_dbn);
- } else
- mlt_log_warning(MLT_CONSUMER_SERVICE(consumer), "video_buffer was NULL, skipping playout\n");
+ // generate SDI frame and playout
+ my_dbn = sdi_playout(video_buffer, this->audio_buffer, &this->audio_format, (channels + 1) / 2, my_dbn);
+
+ // write a JPEG of every X-th frame
+ if (save_jpegs > 0 && counter >= save_jpegs) {
+ consumer_write_JPEG(jpeg_folder, &video_buffer, mlt_service_profile((mlt_service) consumer));
+ counter = 0;
+ } else if (save_jpegs > 0) {
+ counter++;
+ }
+ } else {
+ mlt_log_warning(MLT_CONSUMER_SERVICE(consumer), "Videobuffer was NULL, skipping playout!\n");
+ }
} else {
mlt_log_warning(MLT_CONSUMER_SERVICE(consumer), "WARNING the requested frame is not yet rendered! This will cause image disturbance!\n");
+
+ if (video_buffer) {
+ my_dbn = sdi_playout(video_buffer, this->audio_buffer, &this->audio_format, (channels + 1) / 2, my_dbn);
+ } else {
+ mlt_log_warning(MLT_CONSUMER_SERVICE(consumer), "Videobuffer was NULL, skipping playout!\n");
+ }
}
if (frame != NULL)
mlt_frame_close(frame);
}
+
}
return NULL;
}
// Get the actual object
consumer_SDIstream this = parent->child;
- free(this->path_destination_sdi);
+ free(this->device_file_video);
+ free(this->device_file_audio);
// Now clean up the rest (the close = NULL is a bit nasty but needed for now)
parent->close = NULL;
// Finally clean up this
free(this);
}
+
+/**
+ * Write videobuffer as JPEG to path
+ * @param path
+ **/
+static void consumer_write_JPEG(char * filename, uint8_t **vBuffer, mlt_profile myProfile) {
+
+#ifdef WITH_JPEG
+
+ int bytes_per_pixel = 3; // or 1 for GRACYSCALE images
+ int color_space = JCS_RGB; // or JCS_GRAYSCALE for grayscale images
+
+ uint8_t * buffer_position = *vBuffer;
+ uint8_t image_rgb[myProfile->width * myProfile->height * bytes_per_pixel];
+
+ //convert vBuffer to RGB
+ int i;
+ for (i = 0; i < sizeof(image_rgb) / 6; i++) {
+ int y1 = *(buffer_position++);
+ int cb = *(buffer_position++);
+ int y2 = *(buffer_position++);
+ int cr = *(buffer_position++);
+ convertYCBCRtoRGB(y1, cb, cr, y2, &image_rgb[i * 6]);
+ }
+
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+
+ // this is a pointer to one row of image data
+ JSAMPROW row_pointer[1];
+
+ FILE *outfile = fopen(filename, "wb");
+
+ if (!outfile) {
+ mlt_log_error(NULL, "%s: Error opening output jpeg file %s\n!", __FILE__, filename);
+ return;
+ }
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+ jpeg_stdio_dest(&cinfo, outfile);
+
+ // Setting the parameters of the output file here
+ cinfo.image_width = myProfile->width;
+ cinfo.image_height = myProfile->height;
+ cinfo.input_components = bytes_per_pixel;
+ cinfo.in_color_space = (J_COLOR_SPACE) color_space;
+
+ // default compression parameters, we shouldn't be worried about these
+ jpeg_set_defaults(&cinfo);
+
+ // Now do the compression
+ jpeg_start_compress(&cinfo, TRUE);
+
+ // like reading a file, this time write one row at a time
+ while (cinfo.next_scanline < cinfo.image_height) {
+ row_pointer[0] = &image_rgb[cinfo.next_scanline * cinfo.image_width * cinfo.input_components];
+ jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+ // similar to read file, clean up after we're done compressing
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+ fclose(outfile);
+#endif
+}
+
+/**
+ * converts YCbCr samples to two 32-bit RGB values
+ * @param y1 cb cr and y2 values
+ * @param target pointer
+ * @return 0 upon success
+ **/
+int convertYCBCRtoRGB(int y1, int cb, int cr, int y2, int * target_rgb) {
+
+#ifdef WITH_JPEG
+
+ uint32_t tmp = 0;
+ uint8_t r1, g1, b1, r2, g2, b2;
+
+ //pointer to current output buffer position
+ uint8_t * target_pointer = target_rgb;
+
+ // colorconversion for first pixel and output to rgb buffer
+ /* B1 */
+ tmp = 1.164 * (y1 - 16) + 2.017 * (cb - 128);
+ if (tmp > 255)
+ tmp = 255;
+ if (tmp < 0)
+ tmp = 0;
+ b1 = tmp;
+
+ /* G1 */
+ tmp = 1.164 * (y1 - 16) - 0.813 * (cr - 128) - 0.392 * (cb - 128);
+ if (tmp > 255)
+ tmp = 255;
+ if (tmp < 0)
+ tmp = 0;
+ g1 = tmp;
+
+ /* R1 */
+ tmp = 1.164 * (y1 - 16) + 1.596 * (cr - 128);
+ if (tmp > 255)
+ tmp = 255;
+ if (tmp < 0)
+ tmp = 0;
+ r1 = tmp;
+
+ // colorconversion for second pixel and output to rgb buffer
+ /* B2 */
+ tmp = 1.164 * (y2 - 16) + 2.017 * (cb - 128);
+ if (tmp > 255)
+ tmp = 255;
+ if (tmp < 0)
+ tmp = 0;
+ b2 = tmp;
+
+ /* G2 */
+ tmp = 1.164 * (y2 - 16) - 0.813 * (cr - 128) - 0.392 * (cb - 128);
+ if (tmp > 255)
+ tmp = 255;
+ if (tmp < 0)
+ tmp = 0;
+ g2 = tmp;
+
+ /* R2 */
+ tmp = 1.164 * (y2 - 16) + 1.596 * (cr - 128);
+ if (tmp > 255)
+ tmp = 255;
+ if (tmp < 0)
+ tmp = 0;
+ r2 = tmp;
+
+ // r=y+1.5958*v;
+ // g=y-0.39173*u-0.81290*v;
+ // b=y+2.017*u;
+
+ *target_pointer++ = r1;
+ *target_pointer++ = g1;
+ *target_pointer++ = b1;
+
+ *target_pointer++ = r2;
+ *target_pointer++ = g2;
+ *target_pointer++ = b2;
+
+ return 0;
+#endif
+ return 1;
+}
-/*
+/**
+ *
+ * MLT SDI Consumer:
+ * request video and audio data from MLT and generate an SDI stream
+ *
+ * Copyright (C) Broadcasting Center Europe S.A. http://www.bce.lu
+ * an RTL Group Company http://www.rtlgroup.com
+ * All rights reserved.
+ *
+ * E-mail: support_plasec@bce.lu
*
- * MLT SDI Consumer: request video and audio data from MLT and generate an SDI stream
- * Copyright (C) 2008 Broadcasting Center Europe S.A. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
- *
* DESCRIPTION:
* This software act as interface between the MLT Frameworkas as
- * MLT Consumer and the Linear Systems Ltd. SMPTE 259M-C boards.
+ * MLT Consumer and the Linear Systems Ltd. SMPTE 292M and SMPTE 259M-C boards.
*
* Linear Systems can be contacted at http://www.linsys.ca
*
- * ---------------------------------------------------------------
+ **********************************************************************************
* System : INTeL I686 64Bit
- * OS : Linux SuSE Kernel 2.6.27.23-0.1-default
- * Compiler: gcc (c++)
- * ---------------------------------------------------------------
- * Project : MLT SDI Consumer for SD
+ * OS : Linux SuSE Kernel 2.6.27.39-0.2-default
+ * Compiler: gcc 4.3.2 (c++)
+ **********************************************************************************
+ * Project : MLT SDI Consumer for SD and HD
* Started by : Thomas Kurpick, Dipl.Inf. (FH)
- * ---------------------------------------------------------------
- * This program writes an SDI stream to the SDI driver provided
- * device files. E.g. SDI device file:
- * /dev/sditx0 (SD)
- * /dev/sditx1 (SD)
- * /dev/sditx2 (SD)
- * /dev/sditx4 (SD)
- *
- * Tested with:
- * SDI Master™ PCI
- * SDI Master™ PCIe
- * SDI Master™ FD PCIe LP
- * SDI Master™ Quad/o PCIe LP
+ **********************************************************************************
+ * Supported and tested boards for SD-SDI or HD-SDI Output:
+ * PCI SDI Master™ (model 107)
+ * PCIe SDI Master™ (model 159)
+ * PCIe LP SDI Master™ FD (model 145)
+ * PCIe LP SDI Master™ Quad/o (model 180)
+ * PCIe LP HD-SDI Master™ O (model 193)
*
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include <pthread.h>
-
-// defines
-#define MAX_AUDIO_SAMPLES (1920*2) // 1920 Samples per Channel and we have stereo (48000 Hz /25 fps = 1920 Samples per frame)
-#define MAX_AUDIO_STREAMS (8)
-#define TOTAL_SAMPLES 1728
-#define ANCILLARY_DATA_SAMPLES 280
-#define TOTAL_LINES 625
-#define FIELD_1 1
-#define FIELD_2 2
-#define VERT_BLANKING 0
-#define ACTIVE_VIDEO 1
-
-// Master SDI device
-#define SDI_IOC_MAGIC '='
-#define SDI_IOC_TXGETEVENTS _IOR(SDI_IOC_MAGIC, 2, unsigned int)
-
-// Transmitter event flag bit locations
-#define SDI_EVENT_TX_BUFFER_ORDER 0
-#define SDI_EVENT_TX_BUFFER (1 << SDI_EVENT_TX_BUFFER_ORDER)
-#define SDI_EVENT_TX_FIFO_ORDER 1
-#define SDI_EVENT_TX_FIFO (1 << SDI_EVENT_TX_FIFO_ORDER)
-#define SDI_EVENT_TX_DATA_ORDER 2
-#define SDI_EVENT_TX_DATA (1 << SDI_EVENT_TX_DATA_ORDER)
-
-// function prototypes
-static int sdimaster_init(char *outputpath, int format);
-static int sdimaster_close();
-static int sdimaster_playout(uint8_t *vBuffer, int16_t aBuffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], int audio_streams, int my_DBN);
-
-static int create_SDI_line(uint16_t *buf, int field, int active, uint8_t *video_buffer, int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES],
- int linenumber_sdiframe, int linenumber_video, int my_DBN, int16_t AudioGroupCounter, int16_t AudioGroups2Write, int audio_streams);
-static int writeANC(uint16_t *p, int linenumber_sdiframe, uint16_t DID, int my_DBN, int16_t audio_buffer_A[MAX_AUDIO_SAMPLES], int16_t audio_buffer_B[MAX_AUDIO_SAMPLES],
- int16_t AudioDataPacketCounter, int16_t AudioGroups2Write, int audio_streams);
-static uint16_t checker(uint16_t *DID_pointer);
-
-static uint8_t getZBit(int sample_number);
-static uint8_t getChannelStatusBit(uint16_t sample_number, uint8_t ch);
-static int16_t getNumberOfAudioGroups2Write(int linenuber);
-
-static uint8_t getDBN(int my_DBN);
-
-static uint8_t *pack10(uint8_t *outbuf, uint16_t *inbuf, size_t count);
-
-static int pack_AES_subframe(uint16_t *p, int8_t c, int8_t z, int8_t ch, int32_t audio_sample);
-
-// Filehandler for sdi output
-static int fh_sdi_dest;
-
-struct SDI_atr {
- int status;
- int *fh;
- uint8_t *data;
- size_t framesize;
-} SDI_atr;
-
-// 192bit for AESChannelStatusBits
-uint8_t AESChannelStatusBitArray[192]; // beta array
-//uint8_t AESChannelStatusBitArray[24]; // TODO better way for 24x8bit !!!
+ * Note: PCIe LP HD-SDI Master™ O (model 193) is an VidPort model and supports an
+ * seperate video and audio interface. Device file:
+ * /dev/sdivideotx[] for active video data
+ * /dev/sdiaudiotx[] for pcm audio data
+ *
+ * This mlt consumer use the following device files:
+ * /dev/sditx[] (SD-PAL) up to 8 x AES (8 x stereo / 16 audio channels)
+ * /dev/sdivideotx[] (HD)
+ * /dev/sdiaudiotx[] (HD) up to 4 x AES (4 x stereo / 8 audio channels)
+ *
+ *
+ **********************************************************************************
+ * Last modified by:
+ * Thomas Kurpick 08.Jan.2010
+ * Ver. 2.0
+ *
+ **********************************************************************************
+ *
+ * Consumer properties:
+ * 'dev_video'
+ * 'dev_audio'
+ * 'blanking'
+ * Only to monitor the SDI output a beta version of jpeg-writer is implemented.
+ * 'jpeg_files' a number for output interval
+ * 'save_jpegs' path for image
+ *
+ * EXAMPLE:
+ *
+ * SDI boards with full frame stream (with blanking):
+ * melt video.dv -consumer sdi:/dev/sditx0 buffer=0;
+ * melt video.dv -consumer sdi:/dev/sditx0 buffer=0 blanking=true;
+ * melt video.dv -consumer sdi dev_video=/dev/sditx0 buffer=0 blanking=true;
+ * melt video.dv audio_index=all -consumer sdi dev_video=/dev/sditx0 buffer=0 blanking=true;
+ *
+ * SDI boards without full frame stream (without blanking):
+ * melt -profile atsc_1080i_50 video.mpeg audio_index=1 -consumer sdi dev_video=/dev/sdivideotx0 dev_sdiaudio=/dev/sdiaudiotx0 blanking=false
+ * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_sdiaudio=/dev/sdiaudiotx0 blanking=false
+ * 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
+ *
+ *
+ * SDI output formats and MLT profiles:
+ * #####################################################################################################################################################
+ * ########## SMPTE 274M 1920 x 1080 Image Sample Structure ############################################################################################
+ * #####################################################################################################################################################
+ * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model)
+ * 4 1920 x 1080/60/I interlaced 30 HZ 4 x AES (8 channels) atsc_1080i_60 193
+ * 5 1920 x 1080/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080i_5994 193
+ * 6 1920 x 1080/50/I interlaced 25 HZ 4 x AES (8 channels) atsc_1080i_50 193
+ * 7 1920 x 1080/30/P progressive 30 HZ 4 x AES (8 channels) atsc_1080p_30 193
+ * 8 1920 x 1080/29.97/P progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080p_2997 193
+ * 9 1920 x 1080/25/P progressive 25 HZ 4 x AES (8 channels) atsc_1080p_25 193
+ * 10 1920 x 1080/24/P progressive 24 HZ 4 x AES (8 channels) atsc_1080p_24 193
+ * 11 1920 x 1080/23.98/P progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_1080p_2398 193
+ *
+ * #####################################################################################################################################################
+ * ########## SMPTE 296M 1280 × 720 Progressive Image Sample Structure #################################################################################
+ * #####################################################################################################################################################
+ * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model)
+ * 1 1280 × 720/60 progressive 60 HZ 4 x AES (8 channels) atsc_720p_60 193
+ * 2 1280 × 720/59.94 progressive 60000/1001 ~ 59.97 HZ 4 x AES (8 channels) atsc_720p_5994 193
+ * 3 1280 × 720/50 progressive 50 HZ 4 x AES (8 channels) atsc_720p_50 193
+ * 4 1280 × 720/30 progressive 30 HZ 4 x AES (8 channels) atsc_720p_30 193
+ * 5 1280 × 720/29.97 progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_720p_2997 193
+ * 6 1280 × 720/25 progressive 25 HZ 4 x AES (8 channels) atsc_720p_25 193
+ * 7 1280 × 720/24 progressive 24 HZ 4 x AES (8 channels) atsc_720p_24 193
+ * 8 1280 × 720/23.98 progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_720p_2398 193
+ *
+ * #####################################################################################################################################################
+ * ########## SMPTE 125M 486i 29.97Hz & BT.656 576i 25Hz ###############################################################################################
+ * #####################################################################################################################################################
+ * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model)
+ * SD PAL 720 × 576/50/I interlaced 25 HZ 8 x AES (16 channels) dv_pal 180,145,159,107
+ * SD PAL 720 × 576/50/I interlaced 25 HZ 4 x AES (8 channels) dv_pal 193
+ * 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
+ * SD NTSC 720 × 480/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) sdi_486i_5994 193
+ *
+ **/
+#include "sdi_generator.h"
/*!/brief Initialization of the file handlers for the Playout
- * @param *outputpath: file or SDITX device
- * @param format: 0:PAL, 1:NTSC (unused, PAL is always used)
+ * @param *device_video: file or SDITX device or SDIVIDEOTX device
+ * @param *device_audio: file or SDIAUDIOTX device
+ * @param blanking: true or false (if false the consumer write only active video data without any VANH or HANC)
*/
-static int sdimaster_init(char *outputpath, int format) {
+static int sdi_init(char *device_video, char *device_audio, uint8_t blanking, mlt_profile myProfile) {
+
+ // set device file
+ device_file_video = device_video;
+ device_file_audio = device_audio;
+
+ // set flag for using of blanking with anilary data
+ info.blanking = blanking;
+
+ // set pack methode for SDI word conversion
+ //pack = pack8;
+ //pack = pack10;
+ pack = pack_v210;
+
+ // check format
+ if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1 && myProfile->progressive
+ == 0) {
+ info.fmt = &FMT_1080i60;
+ } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001
+ && myProfile->progressive == 0) {
+ info.fmt = &FMT_1080i5994;
+ } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
+ && myProfile->progressive == 0) {
+ info.fmt = &FMT_1080i50;
+ } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_1080p30;
+ } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_1080p2997;
+ } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_1080p25;
+ } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 24 && myProfile->frame_rate_den == 1
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_1080p24;
+ } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 24000 && myProfile->frame_rate_den == 1001
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_1080p2398;
+ } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 60 && myProfile->frame_rate_den == 1
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_720p60;
+ } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 60000 && myProfile->frame_rate_den == 1001
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_720p5994;
+ } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 50 && myProfile->frame_rate_den == 1
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_720p50;
+ } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_720p30;
+ } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_720p2997;
+ } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_720p25;
+ } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 24 && myProfile->frame_rate_den == 1
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_720p24;
+ } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 24000 && myProfile->frame_rate_den == 1001
+ && myProfile->progressive == 1) {
+ info.fmt = &FMT_720p2398;
+ } else if (myProfile->width == 720 && myProfile->height == 576 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1
+ && myProfile->progressive == 0) {
+ info.fmt = &FMT_576i50;
+ } else if (myProfile->width == 720 && myProfile->height == 480 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001
+ && myProfile->progressive == 0) {
+ info.fmt = &FMT_480i5994;
+ } else {
+ printf("Consumer gets unknown format: %s", myProfile->description);
+ info.fmt = &FMT_576i50;
+ }
+
+ printf("Consumer use format: %s\nProfile: %i %i %i %i %i\n", myProfile->description, myProfile->width, myProfile->height, myProfile->frame_rate_num,
+ myProfile->frame_rate_den, myProfile->progressive);
- // check video format (currently only PAL is available)
- if (format != 0) {
- printf("sdimaster_init get format '%i' ", format);
+ // Check if the format support own blanking (note: model 193 support currently only active video at the video device file)
+ if (info.blanking && info.fmt != &FMT_576i50) {
+ printf("SDI consumer doesn't support blanking(HANC) for this configurred SD board and SDI format. Try arguemnt: blanking=false\n");
return EXIT_FAILURE;
}
- // open destination for SDI output
- if ((fh_sdi_dest = open(outputpath, O_WRONLY | O_CREAT, 0777)) == -1) {
- perror(NULL);
- printf("\ncould not open video output destination!\n");
- return EXIT_FAILURE;
+ if (device_file_video != NULL) {
+ // open file handler for SDI(video) output
+ if ((fh_sdi_video = open(device_file_video, O_WRONLY)) == -1) {
+ perror(NULL);
+ printf("\ncould not open video output destination: %s\n", device_file_video);
+ }
+ printf("SDI consumer use video device file: %s\n", device_file_video);
}
- // small description
- // http://www.sencore.com/newsletter/Nov05/DigAudioChannelStatusBits.htm
- // or
- // http://www.sencore.com/uploads/files/DigAudioChannelStatusBits.pdf
+ // Check if seperat device file for audio must use
+ if (device_file_audio != NULL) {
+ // open file handler for audio output
+ if ((fh_sdi_audio = open(device_file_audio, O_WRONLY | O_CREAT, 0777)) == -1) {
+ perror(NULL);
+ printf("\ncould not open audio output destination: %s\n", device_file_audio);
+ return EXIT_FAILURE;
+ }
+ printf("SDI consumer use audio device file: %s\n", device_file_audio);
+ }
- // create empty AESChannelStatusBitArray
- int i = 0;
- for (i = 0; i < sizeof(AESChannelStatusBitArray) / sizeof(AESChannelStatusBitArray[0]); i++)
- AESChannelStatusBitArray[i] = 0;
+ // if we write our own HANC we need an AES channel status bit array
+ if (info.blanking) {
+
+ // small description
+ // http://www.sencore.com/newsletter/Nov05/DigAudioChannelStatusBits.htm
+ // or
+ // http://www.sencore.com/uploads/files/DigAudioChannelStatusBits.pdf
+
+ // create empty AESChannelStatusBitArray
+ int i = 0;
+ for (i = 0; i < sizeof(AESChannelStatusBitArray) / sizeof(AESChannelStatusBitArray[0]); i++)
+ AESChannelStatusBitArray[i] = 0;
+
+ /**
+ * Professionel Format - Channel Status Bits
+ **/
+ ////// Byte 0 //////
+ AESChannelStatusBitArray[0] = 1; // professional format
+
+ AESChannelStatusBitArray[1] = 0; // PCM Format
+
+ AESChannelStatusBitArray[2] = 1; // Emphasis: [100] No Emphasis
+ AESChannelStatusBitArray[3] = 0; // ^
+ AESChannelStatusBitArray[4] = 0; // ^
+
+ AESChannelStatusBitArray[5] = 0; // locked
+
+ AESChannelStatusBitArray[6] = 0; // sample frequncy Fs: [01]48kHz, [10]44kHz, [11]32kHz
+ AESChannelStatusBitArray[7] = 1; // ^
+ ////// Byte 1 //////
+ AESChannelStatusBitArray[8] = 0; // channel mode: [0000] not indicated, [0001]2channels, [0010]1channel mono, ...
+ AESChannelStatusBitArray[9] = 0; // ^
+ AESChannelStatusBitArray[10] = 0; // ^
+ AESChannelStatusBitArray[11] = 1; // ^
+ ////// Byte 2 //////
+ AESChannelStatusBitArray[19] = 0; // Encoded sample word length [100]20bits,
+ AESChannelStatusBitArray[20] = 0; //
+ AESChannelStatusBitArray[21] = 0; //
+ ////// Byte 3 //////
+ AESChannelStatusBitArray[24] = 0; //
+ AESChannelStatusBitArray[25] = 0; //
+ AESChannelStatusBitArray[26] = 0; //
+ AESChannelStatusBitArray[27] = 0; //
+ AESChannelStatusBitArray[28] = 0; //
+ AESChannelStatusBitArray[29] = 0; //
+ AESChannelStatusBitArray[30] = 0; //
+ AESChannelStatusBitArray[31] = 0; // Multi Channel Mode
+ ////// Byte 4-21 //////
+ //AESChannelStatusBitArray[32-179]= 0;
+ ////// Byte 22 //////
+ AESChannelStatusBitArray[180] = 0; // Reliability Flags
+ AESChannelStatusBitArray[181] = 1; // ^
+ AESChannelStatusBitArray[182] = 1; // ^
+ AESChannelStatusBitArray[183] = 1; // ^
+ ////// Byte 23 //////
+ AESChannelStatusBitArray[184] = 0; // Cyclic Redundancy Check
+ AESChannelStatusBitArray[185] = 1; // ^
+ AESChannelStatusBitArray[186] = 0; // ^
+ AESChannelStatusBitArray[187] = 0; // ^
+ AESChannelStatusBitArray[188] = 1; // ^
+ AESChannelStatusBitArray[189] = 0; // ^
+ AESChannelStatusBitArray[190] = 1; // ^
+ AESChannelStatusBitArray[191] = 1; // ^
+ }
- /**
- * Professionel Format - Channel Status Bits
- **/
- ////// Byte 0 //////
- AESChannelStatusBitArray[0] = 1; // professional format
-
- AESChannelStatusBitArray[1] = 0; // PCM Format
-
- AESChannelStatusBitArray[2] = 1; // Emphasis: [100] No Emphasis
- AESChannelStatusBitArray[3] = 0; // ^
- AESChannelStatusBitArray[4] = 0; // ^
-
- AESChannelStatusBitArray[5] = 0; // locked
-
- AESChannelStatusBitArray[6] = 0; // sample frequncy Fs: [01]48kHz, [10]44kHz, [11]32kHz
- AESChannelStatusBitArray[7] = 1; // ^
- ////// Byte 1 //////
- AESChannelStatusBitArray[8] = 0; // channel mode: [0000] not indicated, [0001]2channels, [0010]1channel mono, ...
- AESChannelStatusBitArray[9] = 0; // ^
- AESChannelStatusBitArray[10] = 0; // ^
- AESChannelStatusBitArray[11] = 1; // ^
- ////// Byte 2 //////
- AESChannelStatusBitArray[19] = 0; // Encoded sample word length [100]20bits,
- AESChannelStatusBitArray[20] = 0; //
- AESChannelStatusBitArray[21] = 0; //
- ////// Byte 3 //////
- AESChannelStatusBitArray[24] = 0; //
- AESChannelStatusBitArray[25] = 0; //
- AESChannelStatusBitArray[26] = 0; //
- AESChannelStatusBitArray[27] = 0; //
- AESChannelStatusBitArray[28] = 0; //
- AESChannelStatusBitArray[29] = 0; //
- AESChannelStatusBitArray[30] = 0; //
- AESChannelStatusBitArray[31] = 0; // Multi Channel Mode
- ////// Byte 4-21 //////
- //AESChannelStatusBitArray[32-179]= 0;
- ////// Byte 22 //////
- AESChannelStatusBitArray[180] = 0; // Reliability Flags
- AESChannelStatusBitArray[181] = 1; // ^
- AESChannelStatusBitArray[182] = 1; // ^
- AESChannelStatusBitArray[183] = 1; // ^
- ////// Byte 23 //////
- AESChannelStatusBitArray[184] = 0; // Cyclic Redundancy Check
- AESChannelStatusBitArray[185] = 1; // ^
- AESChannelStatusBitArray[186] = 0; // ^
- AESChannelStatusBitArray[187] = 0; // ^
- AESChannelStatusBitArray[188] = 1; // ^
- AESChannelStatusBitArray[189] = 0; // ^
- AESChannelStatusBitArray[190] = 1; // ^
- AESChannelStatusBitArray[191] = 1; // ^
+ // set buffer for one line of active video samples
+ line_buffer = (uint16_t*) calloc(info.fmt->samples_per_line, sizeof(uint16_t));
+
+ // calculate and set buffer for the complete SDI frame
+ if (info.fmt != &FMT_576i50 && info.fmt != &FMT_480i5994) {
+ if (info.blanking) {
+ if (pack == pack_v210) {
+ samples = (info.fmt->samples_per_line / 96 * 48) + ((info.fmt->samples_per_line % 96) ? 48 : 0);
+ sdi_frame_size = samples * info.fmt->lines_per_frame * 8 / 3;
+ } else {
+ sdi_frame_size = info.fmt->samples_per_line * info.fmt->lines_per_frame;
+ }
+ } else {
+ if (pack == pack_v210) {
+ samples = (info.fmt->active_samples_per_line / 96 * 48) + ((info.fmt->active_samples_per_line % 96) ? 48 : 0);
+ sdi_frame_size = samples * info.fmt->active_lines_per_frame * 8 / 3;
+ } else {
+ sdi_frame_size = info.fmt->active_samples_per_line * info.fmt->active_lines_per_frame;
+ }
+ }
+ } else {
+ if (info.blanking) {
+ if (pack == pack_v210) {
+ sdi_frame_size = info.fmt->samples_per_line * 4 / 3 * info.fmt->lines_per_frame;
+ } else if (pack == pack8) {
+ sdi_frame_size = info.fmt->samples_per_line * info.fmt->lines_per_frame;
+ } else {
+ sdi_frame_size = info.fmt->samples_per_line * 10 / 8 * info.fmt->lines_per_frame;
+ }
+ } else {
+ if (pack == pack_v210) {
+ sdi_frame_size = info.fmt->active_samples_per_line * 4 / 3 * info.fmt->active_lines_per_frame;
+ } else if (pack == pack8) {
+ sdi_frame_size = info.fmt->active_samples_per_line * info.fmt->active_lines_per_frame;
+ } else {
+ sdi_frame_size = info.fmt->active_samples_per_line * 10 / 8 * info.fmt->active_lines_per_frame;
+ }
+ }
+ }
+
+ // hack/overwrite because we use default the pack_v210() not as befor the pack10()
+ //(*10/8 because we store (TOTAL_SAMPLES*TOTAL_LINES) words with 10 bit in this 8 bit array) )
+ if (info.fmt == &FMT_576i50 && info.blanking) {
+ sdi_frame_size = info.fmt->samples_per_line * 10 / 8 * info.fmt->lines_per_frame;
+ }
+
+ printf("SDI frame size:%li\n", sdi_frame_size);
+
+ // set buffer for the complete SDI frame
+ data = (uint8_t*) calloc(sdi_frame_size, sizeof(uint8_t));
return 1;
}
-//****************************************************************************************
-//***************************** PLAYOUT ************************************************
-//****************************************************************************************
-
-/** Writes video and audio to specified files in SDI format
+/**
+ * Writes video and audio to specified files in SDI format
* @param *vBuffer: Pointer to a video Buffer
- * @param aBuffer: An array of 8 audio channel pairs (2 mono channels)
+ * @param aBuffer[][]
+ * @param *audio_format: mlt audio_format
* @param audio_streams: number of audio streams which have content in aBuffer (available 0-8)
- *
* @return current DBN (data block number of SDI frame)
- *
- */
-static int sdimaster_playout(uint8_t *vBuffer, int16_t aBuffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], int audio_streams, int my_DBN) {
-
- // Buffer for one line of SDI
- uint16_t buf[TOTAL_SAMPLES];
-
- // Buffer for the complete SDI frame
- //(*10/8 because we store (TOTAL_SAMPLES*TOTAL_LINES) words with 10 bit in this 8 bit array) )
- uint8_t data[TOTAL_SAMPLES * 10 / 8 * TOTAL_LINES];
+ **/
+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,
+ int my_DBN) {
// Pointer to the start of data. This is used to fill data line by line
uint8_t *p = data;
- // Size of the SDI frame (also size of data)
- size_t framesize = TOTAL_SAMPLES * 10 / 8 * TOTAL_LINES;
-
//*******************************************************************************************
//**************** Build the SDI frame line by line ****************************************
//*******************************************************************************************
- //counter for the lines
- int i = 0;
- int16_t AudioGroupCounter = 0;
-
- /*#####################################################*/
- /*######## FIELD 1 #######################*/
- /*#####################################################*/
-
- // line 1-22 VERTICAL_BLANKING:23 lines SAV 0x2ac EAV 0x2d8
- for (i = 1; i <= 5; i++) {
- create_SDI_line(buf, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i);
- p = pack10(p, buf, TOTAL_SAMPLES);
- }
- for (i = 6; i <= 8; i++) {
- create_SDI_line(buf, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i);
- p = pack10(p, buf, TOTAL_SAMPLES);
- }
- for (i = 9; i <= 22; i++) {
- create_SDI_line(buf, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i);
- p = pack10(p, buf, TOTAL_SAMPLES);
- }
- // line 23-310 ACTIVE: 287 lines SAV 0x200 EAV 0x274
- int f1counter = 1; // only odd lines
- for (i = 23; i <= 310; i++) {
- create_SDI_line(buf, FIELD_1, ACTIVE_VIDEO, vBuffer, aBuffer, i,
- f1counter, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i);
- p = pack10(p, buf, TOTAL_SAMPLES);
- f1counter += 2;
- }
- i = 311;
- // line 311-312 VERTICAL_BLANKING: 2 lines SAV 0x2ac EAV 0x2d8
- create_SDI_line(buf, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
- p = pack10(p, buf, TOTAL_SAMPLES);
- create_SDI_line(buf, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
- p = pack10(p, buf, TOTAL_SAMPLES);
-
- /*#####################################################*/
- /*######## FIELD 2 ########################*/
- /*#####################################################*/
-
- // line 313-336 VERTICAL_BLANKING: 23 lines SAV 0x3b0 EAV 0x3c4
- create_SDI_line(buf, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
- p = pack10(p, buf, TOTAL_SAMPLES);
-
- create_SDI_line(buf, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
- p = pack10(p, buf, TOTAL_SAMPLES);
-
- create_SDI_line(buf, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
- p = pack10(p, buf, TOTAL_SAMPLES);
-
- create_SDI_line(buf, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
- p = pack10(p, buf, TOTAL_SAMPLES);
-
- create_SDI_line(buf, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
- p = pack10(p, buf, TOTAL_SAMPLES);
-
- create_SDI_line(buf, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
- p = pack10(p, buf, TOTAL_SAMPLES);
-
- // `getAudioGroups2Write()`=0
- for (i = 319; i <= 321; i++) {
- create_SDI_line(buf, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i);
- p = pack10(p, buf, TOTAL_SAMPLES);
- }
- for (i = 322; i <= 335; i++) {
- create_SDI_line(buf, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i);
- p = pack10(p, buf, TOTAL_SAMPLES);
- }
- // line 336-623 ACTIVE: 288 lines SAV 0x31c EAV 0x368
- int f2counter = 2; // only even Lines
- for (i = 336; i <= 623; i++) {
-
- create_SDI_line(buf, FIELD_2, ACTIVE_VIDEO, vBuffer, aBuffer, i,
- f2counter, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i);
- p = pack10(p, buf, TOTAL_SAMPLES);
- f2counter += 2;
- }
- // line 624-625 VERTICAL_BLANKING: 2 lines SAV 0x3b0 EAV 0x3c4
- for (i = 624; i <= 625; i++) {
- create_SDI_line(buf, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0,
- getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams);
- AudioGroupCounter += getNumberOfAudioGroups2Write(i);
- p = pack10(p, buf, TOTAL_SAMPLES);
+
+ /*
+ * if SDI FMT_576i50 for card ASSY 145 or ASSY 159, with access to whole SDI frame buffer
+ * and device_file_audio must be NULL
+ * than we write own audio data,
+ * else
+ * than HD for card ASSY 193
+ */
+ //if (info.fmt == &FMT_576i50 && device_file_audio == NULL && !strcmp(device_file_video, "/dev/sdivideotx0")) {
+ if (info.fmt == &FMT_576i50 && info.blanking) {
+
+ //counter for the lines
+ int i = 0;
+ int16_t AudioGroupCounter = 0;
+
+ /*#####################################################*/
+ /*######## FIELD 1 #######################*/
+ /*#####################################################*/
+
+ info.xyz = &FIELD_1_VERT_BLANKING;
+
+ // line 1-22 VERTICAL_BLANKING:23 lines SAV 0x2ac EAV 0x2d8
+ for (i = 1; i <= 5; i++) {
+ create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+ }
+ for (i = 6; i <= 8; i++) {
+ create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+ }
+ for (i = 9; i <= 22; i++) {
+ create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+ }
+ // line 23-310 ACTIVE: 287 lines SAV 0x200 EAV 0x274
+ info.xyz = &FIELD_1_ACTIVE;
+ int f1counter = 1; // only odd lines
+ for (i = 23; i <= 310; i++) {
+ create_SD_SDI_Line(line_buffer, &info, FIELD_1, ACTIVE_VIDEO, vBuffer, aBuffer, i, f1counter, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+ f1counter += 2;
+ }
+ i = 311;
+ // line 311-312 VERTICAL_BLANKING: 2 lines SAV 0x2ac EAV 0x2d8
+ info.xyz = &FIELD_1_VERT_BLANKING;
+ create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+ create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+
+ /*#####################################################*/
+ /*######## FIELD 2 ########################*/
+ /*#####################################################*/
+
+ info.xyz = &FIELD_2_VERT_BLANKING;
+
+ // line 313-336 VERTICAL_BLANKING: 23 lines SAV 0x3b0 EAV 0x3c4
+ create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+
+ create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+
+ create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+
+ create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+
+ create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+
+ create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i++);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+
+ // `getAudioGroups2Write()`=0
+ for (i = 319; i <= 321; i++) {
+ create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+ }
+ for (i = 322; i <= 335; i++) {
+ create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+ }
+ // line 336-623 ACTIVE: 288 lines SAV 0x31c EAV 0x368
+ info.xyz = &FIELD_2_ACTIVE;
+ int f2counter = 2; // only even Lines
+ for (i = 336; i <= 623; i++) {
+
+ create_SD_SDI_Line(line_buffer, &info, FIELD_2, ACTIVE_VIDEO, vBuffer, aBuffer, i, f2counter, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+ f2counter += 2;
+ }
+ // line 624-625 VERTICAL_BLANKING: 2 lines SAV 0x3b0 EAV 0x3c4
+ info.xyz = &FIELD_2_VERT_BLANKING;
+ for (i = 624; i <= 625; i++) {
+ create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter,
+ getNumberOfAudioGroups2Write(i), audio_streams);
+ AudioGroupCounter += getNumberOfAudioGroups2Write(i);
+ p = pack10(p, line_buffer, info.fmt->samples_per_line);
+ }
+
+ } else { // use HD board without blanking
+
+ // start with first even line
+ active_video_line = 1;
+
+ /* *****************************************
+ * *********** LINE DISTRIBUTION ***********
+ * *****************************************
+ *
+ * << decide form of scanning (interlaced || progressive) >>
+ * if (interlaced)
+ * << decide lines per frame (1125 || 625 || 525) >>
+ * if(1125) 1080x1920 HD
+ * than create lines
+ * else if(625) 576x720 PAL
+ * than create lines
+ * else (525) 486x720 NTSC
+ * than create lines
+ * else (progressive)
+ * << decide resolution (1125 || 750) >>
+ * if(1125) 1080x1920 HD
+ * than create lines
+ * else(750) 720x1280 HD
+ * than create lines
+ *
+ **/
+
+ // Generate a frame
+ if (info.fmt->interlaced) {
+
+ /****************************************
+ * INTERLACED
+ ****************************************/
+
+ if (info.fmt->lines_per_frame == 1125) {
+
+ if (info.blanking) {
+ elements = info.fmt->samples_per_line;
+ info.xyz = &FIELD_1_VERT_BLANKING;
+ for (info.ln = 1; info.ln <= 20; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ } else {
+ elements = info.fmt->active_samples_per_line;
+ }
+ info.xyz = &FIELD_1_ACTIVE;
+ for (info.ln = 21; info.ln <= 560; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
+ p = pack(p, line_buffer, elements);
+ active_video_line += 2;
+ }
+ if (info.blanking) {
+ info.xyz = &FIELD_1_VERT_BLANKING;
+ for (info.ln = 561; info.ln <= 563; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ info.xyz = &FIELD_2_VERT_BLANKING;
+ for (info.ln = 564; info.ln <= 583; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ }
+ // start with first odd line
+ active_video_line = 2;
+
+ info.xyz = &FIELD_2_ACTIVE;
+ for (info.ln = 584; info.ln <= 1123; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
+ p = pack(p, line_buffer, elements);
+ active_video_line += 2;
+ }
+ if (info.blanking) {
+ info.xyz = &FIELD_2_VERT_BLANKING;
+ for (info.ln = 1124; info.ln <= 1125; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ }
+ } else if (info.fmt->lines_per_frame == 625) {
+
+ elements = info.fmt->active_samples_per_line;
+
+ // start with first even line
+ active_video_line = 1;
+
+ /**
+ * Generate an SDI PAL frame
+ **/
+ if (info.blanking) {
+ info.xyz = &FIELD_1_VERT_BLANKING;
+ for (info.ln = 1; info.ln <= 22; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ }
+ info.xyz = &FIELD_1_ACTIVE;
+ for (info.ln = 23; info.ln <= 310; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
+ p = pack(p, line_buffer, elements);
+ active_video_line += 2;
+ }
+ if (info.blanking) {
+ info.xyz = &FIELD_1_VERT_BLANKING;
+ for (info.ln = 311; info.ln <= 312; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ info.xyz = &FIELD_2_VERT_BLANKING;
+ for (info.ln = 313; info.ln <= 335; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ }
+
+ // start with first odd line
+ active_video_line = 2;
+
+ info.xyz = &FIELD_2_ACTIVE;
+ for (info.ln = 336; info.ln <= 623; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
+ p = pack(p, line_buffer, elements);
+ active_video_line += 2;
+ }
+ if (info.blanking) {
+ info.xyz = &FIELD_2_VERT_BLANKING;
+ for (info.ln = 624; info.ln <= 625; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ }
+ } else if (info.fmt->lines_per_frame == 525) {
+
+ /**
+ * Generate an SDI NTSC frame
+ **/
+ elements = info.fmt->active_samples_per_line;
+
+ active_video_line = 1;
+
+ if (info.blanking) {
+ info.xyz = &FIELD_1_VERT_BLANKING;
+ for (info.ln = 1; info.ln <= 15; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ for (info.ln = 16; info.ln <= 16; info.ln++) {
+ info.xyz = &FIELD_1_ACTIVE;
+ mkline(line_buffer, &info, VERT_BLANKING);
+ p = pack(p, line_buffer, elements);
+ }
+ }
+
+ info.xyz = &FIELD_1_ACTIVE;
+ // 3 lines opt. video data
+ for (info.ln = 17; info.ln <= 19; info.ln++) {
+ mkline(line_buffer, &info, BLACK);
+ p = pack(p, line_buffer, elements);
+ }
+ for (info.ln = 20; info.ln <= 259; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
+ p = pack(p, line_buffer, elements);
+ active_video_line += 2;
+ }
+ if (info.blanking) {
+ info.xyz = &FIELD_1_VERT_BLANKING;
+ for (info.ln = 260; info.ln <= 261; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ info.xyz = &FIELD_2_VERT_BLANKING;
+ // 7 lines vertical data
+ for (info.ln = 262; info.ln <= 269; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ // 9 lines opt. video data ?? // TODO have look to SMPTE
+ for (info.ln = 270; info.ln <= 278; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+
+ }
+
+ active_video_line = 0;
+ // 3 lines opt. video data
+ info.xyz = &FIELD_2_ACTIVE;
+ for (info.ln = 279; info.ln <= 281; info.ln++) {
+ mkline(line_buffer, &info, BLACK);
+ p = pack(p, line_buffer, elements);
+ }
+ for (info.ln = 282; info.ln <= 521; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer);
+ p = pack(p, line_buffer, elements);
+ active_video_line += 2;
+ }
+ if (info.blanking) {
+ info.xyz = &FIELD_2_VERT_BLANKING;
+ for (info.ln = 522; info.ln <= 525; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ }
+ }
+ } else {
+
+ /****************************************
+ * PROGRESSIVE
+ ****************************************/
+
+ // start with first line numerber
+ active_video_line = 0;
+
+ if (info.fmt->lines_per_frame == 1125) {
+ if (info.blanking) {
+ elements = info.fmt->samples_per_line;
+ info.xyz = &FIELD_1_VERT_BLANKING;
+ for (info.ln = 1; info.ln <= 41; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ } else {
+ elements = info.fmt->active_samples_per_line;
+ }
+ info.xyz = &FIELD_1_ACTIVE;
+ for (info.ln = 42; info.ln <= 1121; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, active_video_line++, ACTIVE_VIDEO, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ if (info.blanking) {
+ info.xyz = &FIELD_1_VERT_BLANKING;
+ for (info.ln = 1122; info.ln <= 1125; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ }
+ } else {
+ if (info.blanking) {
+ elements = info.fmt->samples_per_line;
+ info.xyz = &FIELD_1_VERT_BLANKING;
+ for (info.ln = 1; info.ln <= 25; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ } else {
+ elements = info.fmt->active_samples_per_line;
+ }
+ info.xyz = &FIELD_1_ACTIVE;
+ for (info.ln = 26; info.ln <= 745; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, active_video_line++, ACTIVE_VIDEO, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ if (info.blanking) {
+ info.xyz = &FIELD_1_VERT_BLANKING;
+ for (info.ln = 746; info.ln <= 750; info.ln++) {
+ create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer);
+ p = pack(p, line_buffer, elements);
+ }
+ }
+ }
+ }
}
// sum of bytes that have already been written to file
// store actual written bytes per 'write()
int written_bytes = 0;
- /*****************************************/
- /**** WRITE BUFFER TO FILEHANDLE *********/
- /*****************************************/
-
+ /**
+ * WRITE BUFFER TO FILEHANDLE
+ **/
// Write the complete frame to output
// The "while" is necessary because the sdi device file does not take the complete frame at once
- while (bytes < framesize) {
- if ((written_bytes = write(fh_sdi_dest, data + bytes, framesize - bytes)) < 0) {
- fprintf(stderr, "\nunable to write SDI.\n");
+ written_bytes = 0;
+ while (bytes < sdi_frame_size) {
+
+ if ((written_bytes = write(fh_sdi_video, data + bytes, sdi_frame_size - bytes)) < 0) {
+ fprintf(stderr, "\nunable to write SDI video.\n");
return -1;
}
bytes += written_bytes;
// Check for events of the SDI board
unsigned int val;
- // printf ("Getting the transmitter event flags.\n");
- if (ioctl(fh_sdi_dest, SDI_IOC_TXGETEVENTS, &val) < 0) {
+ if (ioctl(fh_sdi_video, SDI_IOC_TXGETEVENTS, &val) < 0) {
// Maybe this is not an SDI device...
-
- // fprintf (stderr, "SDI output:");
- // perror ("unable to get the transmitter event flags");
+ fprintf(stderr, "SDI VIDEO output:");
+ perror("unable to get the transmitter event flags");
} else if (val) {
if (val & SDI_EVENT_TX_BUFFER) {
- printf("SDI driver transmit buffer queue underrun "
+ printf("SDI VIDEO driver transmit buffer queue underrun "
"detected.\n");
- sleep(5);
}
if (val & SDI_EVENT_TX_FIFO) {
- printf("SDI onboard transmit FIFO underrun detected.\n");
-
+ printf("SDI VIDEO onboard transmit FIFO underrun detected.\n");
// TODO react
}
if (val & SDI_EVENT_TX_DATA) {
- // printf("SDI transmit data change detected.\n");
+ printf("SDI VIDEO transmit data change detected.\n");
}
}
+ fflush(stdout);
+ }
+
+ // if available write audio data
+ if (fh_sdi_audio) {
+
+ // count writen bytes
+ written_bytes = 0;
+
+ // set number of samples and cut by 1600 if NTSC (handle problem of real time encoding of NTSC frequencies)
+ //size_t samples_total_per_track = audio_format->samples == 1601 || audio_format->samples == 1602 ? 1600 : audio_format->samples; // TODO buffer underrun by NTSC frequencs because of 3/2 pull down
+ size_t samples_total_per_track = audio_format->samples;
+ uint16_t sample_number = 0;
+ size_t channels_per_track_total = 2;
+ uint8_t stream_number = 0;
+
+ //printf("samples_total_per_track:%li\n", samples_total_per_track);
+
+ // to write blockwise 2 samples of one track we must claculate the number of bytes we want to write per write-session
+ // 2samples = 2x16Bit = 32Bit = 4Byte
+ // 2samples = 2x32Bit = 64Bit = 8Byte
+ // set total bytes per session
+ size_t bytes_total = 0;
+ bytes_total = audio_format->aformat == mlt_audio_s16 ? channels_per_track_total * sizeof(int16_t) : bytes_total;
+ bytes_total = audio_format->aformat == mlt_audio_s32 ? channels_per_track_total * sizeof(int32_t) : bytes_total; // TODO sdi board must be pre-configured for 32bit samples!!!!
+
+ // write all samples of all streams interleaved
+ /**
+ * aBuffer[track0]+sample1
+ * aBuffer[track0]+sample2
+ * aBuffer[track1]+sample1
+ * aBuffer[track1]+sample2
+ * aBuffer[track.]+sample1
+ * aBuffer[track.]+sample2
+ *
+ * aBuffer[track0]+sample3
+ * aBuffer[track0]+sample4
+ * aBuffer[track1]+sample3
+ * aBuffer[track1]+sample4
+ * aBuffer[track.]+sample3
+ * aBuffer[track.]+sample4
+ *
+ * aBuffer[track0]+sample5
+ * aBuffer[track0]+sample6
+ * aBuffer[track1]+sample5
+ * aBuffer[track1]+sample6
+ * aBuffer[track.]+sample5
+ * aBuffer[track.]+sample6
+ **/
+ int sum_written_bytes = 0;
+ int sum_written_bytes_a = 0;
+ int sum_written_bytes_b = 0;
+
+ // write all samples per track
+ while (sample_number < samples_total_per_track) {
+
+ stream_number = 0;
+
+ /**
+ * Because we have and write a fix number of audio streams to SDI board:
+ * we have a actual number of real audio tracks and a rest number of pseudo tracks
+ **/
+ // write all streams
+ while (stream_number < audio_streams) {
+
+ // write for every stream n samples
+ // n = number of channels per stream
+ written_bytes = 0;
+ while (written_bytes < bytes_total) {
+ written_bytes += write(fh_sdi_audio, (uint8_t *) aBuffer[stream_number] + sample_number * bytes_total + written_bytes, bytes_total
+ - written_bytes);
+ }
+ sum_written_bytes += written_bytes;
+ sum_written_bytes_a += written_bytes;
+
+ stream_number++;
+ }
+
+ // write pseudo tracks
+ // now fill rest of audio tracks with NULL or copy of first track
+ while (stream_number < 4) { // TODO linsys board model 193 have a limit to 4 AES groups (=4streams,8channels)
+
+ // write for every stream n samples
+ // n = number of channels per stream
+ written_bytes = 0;
+ while (written_bytes < bytes_total) {
+ written_bytes += write(fh_sdi_audio, (uint8_t *) aBuffer[0] + sample_number * bytes_total + written_bytes, bytes_total - written_bytes);
+ }
+ sum_written_bytes += written_bytes;
+ sum_written_bytes_b += written_bytes;
+
+ stream_number++;
+ }
+
+ sample_number++;
+
+// // Check for events of the SDI board (only firmware 0.9)
+// unsigned int val;
+// if (ioctl(fh_sdi_audio, SDI_IOC_TXGETEVENTS, &val) < 0) {
+// //Maybe this is not an SDI device...
+// fprintf(stderr, "SDI AUDIO output:");
+// perror("unable to get the transmitter event flags");
+// } else if (val) {
+// if (val & SDI_EVENT_TX_BUFFER) {
+// printf("SDI AUDIO driver transmit buffer queue underrun "
+// "detected.\n");
+// }
+// if (val & SDI_EVENT_TX_FIFO) {
+// printf("SDI AUDIO onboard transmit FIFO underrun detected.\n");
+// //TODO react
+// }
+// if (val & SDI_EVENT_TX_DATA) {
+// printf("SDI AUDIO transmit data change detected.\n");
+// }
+// }
+ }
}
return getDBN(my_DBN);
} // end sdimaster_playout()
-// ****************************************************************************************
-// *************************** Create Line **********************************************
-// ****************************************************************************************
+
+//****************************************************************************************
+//*************************** Create Line **********************************************
+//****************************************************************************************
/** generate one SDI line
* @param *buf: buffer to hold the line
* @param field: size of the video Buffer
* @param active: v-blank or active-video
* @param *video_buffer: video buffer
- * @param audio_buffer: array of 8 channel pairs
+ * @param *audio_buffer2: 1.audio buffer ch1-ch2
+ * @param *audio_buffer1: 2.audio buffer ch2-ch3
* @param line: linenumber
* @param AudioGroupCounter: count written AudioGroup
* @param AudioGroups2Write: number of samples to write
* @param audio_streams: number of audio streams to integrate
*/
-static int create_SDI_line(uint16_t *buf, int field, int active, uint8_t *video_buffer, int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES],
- int linenumber_sdiframe, int linenumber_video, int my_DBN, int16_t AudioGroupCounter, int16_t AudioGroups2Write, int audio_streams) {
+static inline int create_SD_SDI_Line(uint16_t *buf, const struct line_info *info, int field, int active, uint8_t *video_buffer,
+ int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], int linenumber_sdiframe, int active_video_line, int my_DBN, int16_t AudioGroupCounter,
+ int16_t AudioGroups2Write, int audio_streams) {
// write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2)
- // *************************************************************************
+ // *************************************************************************
// 625 lines: | EAV | ANC | SAV | [CbY1CrY2] |
- // *************************************************************************
+ // *************************************************************************
// 1728 SDI-words: | 4 | 280 | 4 | 720+360+360=1440 |
- // *************************************************************************
+ // *************************************************************************
// points to current position in line
uint16_t *p = buf;
- // XYZ word
- uint16_t sav, eav;
-
- // Set XYZ-word for each case
- switch (field) {
- case FIELD_1:
- switch (active) {
- case VERT_BLANKING:
- eav = 0x2d8; // 0xb6 << 2; // set bits for XYZ-word : [MSB:1][F][V][H][P3][P2][P1][P0][0][LSB:0]
- sav = 0x2ac; // 0xab << 2;
- break;
- case ACTIVE_VIDEO:
- eav = 0x274; // 0x9d << 2;
- sav = 0x200; // 0x80 << 2;
- break;
- default:
- return -1;
- }
- break;
- case FIELD_2:
- switch (active) {
- case VERT_BLANKING:
- eav = 0x3c4; // 0xf1 << 2;
- sav = 0x3b0; // 0xec << 2;
- break;
- case ACTIVE_VIDEO:
- eav = 0x368; // 0xda << 2;
- sav = 0x31c; // 0xc7 << 2;
- break;
- default:
- return -1;
- }
- break;
- default:
- return -1;
- }
- // #########################################################################################
+ //#########################################################################################
/* TRS Timing Reference Signal for EAV
* [3ff]
* [000]
* [000]
* [XYZ-Wort]
* */
+
*p++ = 0x3ff;
*p++ = 0x000;
*p++ = 0x000;
- *p++ = eav;
- // #########################################################################################
+ *p++ = info->xyz->eav;
+ //#########################################################################################
/* ANC Ancillary Data with AES
*
// write ANC Data and get number of samples are written
// step with `p` += to the number of written samples
- // Audio Group 1 with AES Frame 1 - 2
- if (audio_streams > 0 && audio_streams <= 2) {
- p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write, audio_streams);
- }
+ //printf("audio_streams:%i\n",audio_streams);
- // Audio Group 2 with AES Frame 3 - 4
- if (audio_streams > 2 && audio_streams <= 4) {
- p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write, audio_streams);
+ // 1 stream, Audio Group 1 with AES Frame 1 - 2
+ if (audio_streams == 1) {
+ p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[0], AudioGroupCounter, AudioGroups2Write);
+ }
+ // 2 streams, Audio Group 1 with AES Frame 1 - 2
+ if (audio_streams == 2) {
+ p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
+ }
+ // 3 streams, Audio Group 2 with AES Frame 1 - 4
+ if (audio_streams == 3) {
+ p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
+ p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[2], AudioGroupCounter, AudioGroups2Write);
+ }
+ // 4 streams, Audio Group 2 with AES Frame 1 - 4
+ if (audio_streams == 4) {
+ p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
+ p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
+ }
+ // 5 streams, Audio Group 3 with AES Frame 1 - 6
+ if (audio_streams == 5) {
+ p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
+ p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
+ p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[4], AudioGroupCounter, AudioGroups2Write);
+ }
+ // 6 streams, Audio Group 3 with AES Frame 1 - 6
+ if (audio_streams == 6) {
+ p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
+ p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
+ p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write);
+ }
+ // 7 streams, Audio Group 4 with AES Frame 1 - 7
+ if (audio_streams == 7) {
+ p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
+ p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
+ p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write);
+ p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[6], AudioGroupCounter, AudioGroups2Write);
+ }
+ // 8 streams, Audio Group 4 with AES Frame 1 - 7
+ if (audio_streams == 8) {
+ p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write);
+ p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write);
+ p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write);
+ p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[7], AudioGroupCounter, AudioGroups2Write);
}
-
- // Audio Group 3 with AES Frame 5 - 6
- if (audio_streams > 4 && audio_streams <= 6)
- p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write, audio_streams);
-
- if (audio_streams > 6 && audio_streams <= 8)
- // Audio Group 4 with AES Frame 6 - 7
- p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[7], AudioGroupCounter, AudioGroups2Write, audio_streams);
// Fill ANC data in until the end (position(p) to `ANCILLARY_DATA_SAMPLES`)
while (p < (buf + ANCILLARY_DATA_SAMPLES + 4)) {
*p++ = 0x200;
*p++ = 0x040;
}
- // #########################################################################################
+ //#########################################################################################
// TRS Timing Reference Signal for SAV
*p++ = 0x3ff;
*p++ = 0x000;
*p++ = 0x000;
- *p++ = sav;
- // #########################################################################################
+ *p++ = info->xyz->sav;
+ //#########################################################################################
- // If VBlank then fill the line with 0x200 and 0x040
+ // If VBlank then fill the line with 0x200 and 0x040 (total black)
switch (active) {
default:
case VERT_BLANKING:
- while (p < (buf + TOTAL_SAMPLES)) {
+ while (p < (buf + info->fmt->samples_per_line)) {
*p++ = 0x200;
*p++ = 0x040;
}
break;
case ACTIVE_VIDEO:
- // Insert the Video into the Line
- while (p < (buf + TOTAL_SAMPLES)) { // fill the rest of the line with active video
+ // Insert the video into the line
+ while (p < (buf + info->fmt->samples_per_line)) { // fill the rest of the line with active video
+
+ // shift "<< 2" because 8 bit data in 10 bit word
// Because we skip the first line of video, it can happen that we read too far in the buffer
- if (linenumber_video >= 576)
- linenumber_video = 575;
+ if (active_video_line >= info->fmt->active_lines_per_frame) {
+ active_video_line = info->fmt->active_lines_per_frame - 1; // in SD PAL was set 575
+ }
- *p = video_buffer[(linenumber_video * 1440) + ((p - 288) - buf) + 1] << 2; // Cb
+ *p = video_buffer[(active_video_line * 1440) + ((p - 288) - buf) + 1] << 2; // Cb
p++;
if (*(p - 1) < 0x040)
*(p - 1) = 0x040; // check values
if (*(p - 1) > 0x3c0)
*(p - 1) = 0x3c0;
- *p = video_buffer[(linenumber_video * 1440) + ((p - 288) - buf) - 1] << 2; // Y1
+ *p = video_buffer[(active_video_line * 1440) + ((p - 288) - buf) - 1] << 2; // Y1
p++;
if (*(p - 1) < 0x040)
*(p - 1) = 0x040;
if (*(p - 1) > 0x3ac)
*(p - 1) = 0x3ac;
- *p = video_buffer[(linenumber_video * 1440) + ((p - 288) - buf) + 1] << 2; // Cr
+ *p = video_buffer[(active_video_line * 1440) + ((p - 288) - buf) + 1] << 2; // Cr
p++;
if (*(p - 1) < 0x040)
*(p - 1) = 0x040;
if (*(p - 1) > 0x3c0)
*(p - 1) = 0x3c0;
- *p = video_buffer[(linenumber_video * 1440) + ((p - 288) - buf) - 1] << 2; // Y2
+ *p = video_buffer[(active_video_line * 1440) + ((p - 288) - buf) - 1] << 2; // Y2
p++;
if (*(p - 1) < 0x040)
*(p - 1) = 0x040;
return 0;
}
-static int writeANC(uint16_t *p, int videoline_sdiframe, uint16_t DID, int my_DBN, int16_t audio_buffer_A[MAX_AUDIO_SAMPLES], int16_t audio_buffer_B[MAX_AUDIO_SAMPLES], int16_t AudioGroupCounter,
- int16_t AudioGroups2Write, int audio_streams) {
+/**
+ * create_HD_SDI_Line - generate one line
+ * @buf: pointer to a buffer
+ * @info: pointer to a line information structure
+ * @active_video_line
+ * @active:
+ * @video_buffer: pattern
+ *
+ * Returns a negative error code on failure and zero on success.
+ **/
+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) {
+ uint16_t *p = buf, *endp, ln;
+ uint16_t samples = info->blanking ? info->fmt->samples_per_line : info->fmt->active_samples_per_line;
+
+ if (info->blanking) {
+
+ // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2)
+ // Example SD PAL:
+ // *************************************************************************
+ // 625 lines: | EAV | ANC | SAV | [CbY1CrY2] |
+ // *************************************************************************
+ // 1728 SDI-words: | 4 | 280 | 4 | 720+360+360=1440 |
+ // *************************************************************************
+
+ // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2)
+ // Example HD 1080i:
+ // *************************************************************************
+ // 1125 lines: | EAV | LN | CRC | ANC | SAV | [CbY1CrY2] |
+ // *************************************************************************
+ // 5280 SDI-words: | 6 | 4 | 4 | 280 | 6 | 1920+720+720=3840 |
+ // *************************************************************************
+
+ if (info->fmt == &FMT_576i50) {
+ /* EAV */
+ *p++ = 0x3ff;
+ *p++ = 0x000;
+ *p++ = 0x000;
+ *p++ = info->xyz->eav;
+ } else {
+ /* EAV */
+ *p++ = 1023;
+ *p++ = 1023;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = info->xyz->eav;
+ *p++ = info->xyz->eav;
+ /* LN */
+ ln = ((info->ln & 0x07f) << 2) | (~info->ln & 0x040) << 3;
+ *p++ = ln;
+ *p++ = ln;
+ ln = ((info->ln & 0x780) >> 5) | 0x200;
+ *p++ = ln;
+ *p++ = ln;
+ /* CRC, added by serializer */
+ *p++ = 512;
+ *p++ = 64;
+ *p++ = 512;
+ *p++ = 64;
- /* ANC Ancillary
- *
- * [ADF][ADF][ADF][DID][DBN][DC][UDW]...[UDW][CS]
+ }
+
+ /* Horizontal blanking */
+ while (p < (buf + info->fmt->samples_per_line - info->fmt->active_samples_per_line - 4)) {
+ *p++ = 512;
+ *p++ = 64;
+ *p++ = 512;
+ *p++ = 64;
+ }
+
+ if (info->fmt == &FMT_576i50) {
+ /* SAV */
+ *p++ = 0x3ff;
+ *p++ = 0x000;
+ *p++ = 0x000;
+ *p++ = info->xyz->sav;
+ } else {
+ /* SAV */
+ *p++ = 1023;
+ *p++ = 1023;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = info->xyz->sav;
+ *p++ = info->xyz->sav;
+ }
+ }
+ /* Active region */
+ endp = p;
+
+ switch (active) {
+ default:
+ case VERT_BLANKING:
+ while (p < (buf + samples)) {
+ *p++ = 512;
+ *p++ = 64;
+ *p++ = 512;
+ *p++ = 64;
+ }
+ break;
+ case ACTIVE_VIDEO:
+
+ {
+
+ while (p < (buf + samples)) {
+
+ if (active_video_line >= info->fmt->active_lines_per_frame) {
+ active_video_line = info->fmt->active_lines_per_frame - 1;
+ }
+
+ // sample = (active_video_line * info->fmt->active_samples_per_line) + (p - buf) + 1;
+ // *p++ = sample > 1440 ? 735 : (video_buffer[sample] << 2);
+ // sample = (active_video_line * info->fmt->active_samples_per_line) + (p - buf) - 1;
+ // *p++ = sample > 1440 ? 335 : (video_buffer[sample] << 2);
+ // sample = (active_video_line * info->fmt->active_samples_per_line) + (p - buf) + 1;
+ // *p++ = sample > 1440 ? 793 : (video_buffer[sample] << 2);
+ // sample = (active_video_line * info->fmt->active_samples_per_line) + (p - buf) - 1;
+ // *p++ = sample > 1440 ? 335 : (video_buffer[sample] << 2);
+
+ *p = video_buffer[(active_video_line * info->fmt->active_samples_per_line) + (p - buf) + 1] << 2; // Cb
+ p++;
+ // check values, but need manny resources
+ // if (*(p - 1) < 0x040)
+ // *(p - 1) = 0x040;
+ // if (*(p - 1) > 0x3c0)
+ // *(p - 1) = 0x3c0;
+ //
+ *p = video_buffer[(active_video_line * info->fmt->active_samples_per_line) + (p - buf) - 1] << 2; // Y1
+ p++;
+ // if (*(p - 1) < 0x040)
+ // *(p - 1) = 0x040;
+ // if (*(p - 1) > 0x3ac)
+ // *(p - 1) = 0x3ac;
+ //
+ *p = video_buffer[(active_video_line * info->fmt->active_samples_per_line) + (p - buf) + 1] << 2; // Cr
+ p++;
+ // if (*(p - 1) < 0x040)
+ // *(p - 1) = 0x040;
+ // if (*(p - 1) > 0x3c0)
+ // *(p - 1) = 0x3c0;
+ //
+ *p = video_buffer[(active_video_line * info->fmt->active_samples_per_line) + (p - buf) - 1] << 2; // Y2
+ p++;
+ // if (*(p - 1) < 0x040)
+ // *(p - 1) = 0x040;
+ // if (*(p - 1) > 0x3ac)
+ // *(p - 1) = 0x3ac;
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+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,
+ int16_t AudioGroups2Write) {
+
+ /**
+ * ANC Ancillary Data (vgl. SMPTE 291-M page 6 )
+ * [ADF][ADF][ADF][DID][DBN][DC][UDW]...[UDW][CS]
*
- * */
+ **/
// save only current position for return value
uint16_t *pp = p;
uint16_t buffer = 0; // set all explicit to zero, special the bit9 for parity
// parity_counter
int8_t parity_counter = 0;
- // var `i` for forloops
- int i = 0;
if (AudioGroups2Write > 0) {
- // printf("\n %i\n", (audiobuffer_line/8));
-
- // Ancillary Data (vgl. SMPTE 291-M page 6 )
// 3 ADF (Ancillary Data Flag)
*p++ = 0x000;
// save DID for checker()
uint16_t *DID_pointer = p;
*p++ = DID;// (AES Audio Data, Group
-
- // *p++ = 0x2FF; // (AES Audio Data, Group1=0x2FF)
- // *p++ = 0x1FD; // (AES Audio Data, Group2=0x1FD)
- // *p++ = 0x1FB; // (AES Audio Data, Group3=0x1FB)
- // *p++ = 0x2F9; // (AES Audio Data, Group4=0x2F9)
+ // *p++ = 0x2FF; // (AES Audio Data, Group1=0x2FF)
+ // *p++ = 0x1FD; // (AES Audio Data, Group2=0x1FD)
+ // *p++ = 0x1FB; // (AES Audio Data, Group3=0x1FB)
+ // *p++ = 0x2F9; // (AES Audio Data, Group4=0x2F9)
// 1 DBN (Data Block Number) inactiv: 1000000000 b9,b8,b7-b0 ; SMPTE 272-M chapter15.1
- // *p++ = 0x200;
-
- // 1 DBN should start with previus DBN of SDI-Frame
- // -need "previus DBN" or "current framenumber"
- // SDI-LINE DBN
- // [1] [1] << start sdi frame >>
- // [2] [2]
- // [.] [.]
- // [255] [255]
- // [256] [1]
- // [257] [2]
- // [.] [.]
- // [510] [255]
- // [511] [1]
- // [512] [2]
- // [.] [.]
- // [625] [115] << end sdi frame >>
- // [1] [116] << start sdi frame >>
+ // *p++ = 0x200;
+
+ // 1 DBN (dynamic version0.1-beta ), should start with previus DBN of SDI-Frame
+ // -need "previus DBN" or "current framenumber"
+ // SDI-LINE: DBN:
+ // [1] [1] << start sdi frame
+ // [2] [2]
+ // [.] [.]
+ // [255] [255]
+ // [256] [1]
+ // [257] [2]
+ // [.] [.]
+ // [510] [255]
+ // [511] [1]
+ // [512] [2]
+ // [.] [.]
+ // [625] [115] << end sdi frame
+ // [1] [116] << start sdi frame
// Accuracy of videoline_sdiframe(1 up to 625) to 8bit (1-255)
- // buffer = ((videoline_sdiframe-1) % 255)+1;
+ //buffer = ((videoline_sdiframe-1) % 255)+1;
buffer = my_DBN;
parity_counter = 0;
// count binary ones for parity
+ int i = 0;
for (i = 0; i < 8; i++) {
if (buffer & (1 << i))
parity_counter++;
}
- if ((parity_counter % 2) == 0) { // else leave the 0
+ if ((parity_counter % 2) == 0) { //else leave the 0
buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
} else {
buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
if (buffer & (1 << i))
parity_counter++;
}
- if ((parity_counter%2)==0) { // else leave the 0
+ if ((parity_counter%2)==0) { //else leave the 0
buffer+= 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
} else {
buffer+= 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
int16_t sample_number=0;
int16_t counter = 0;
// write subframes:
- // = n x 1AudioGroup
+ // = n x 1 AudioGroup
// = n x 2 x 1AESFrame
// = n x 2 x 2samples
- // = 4samples
+ // = 4 samples
// = 4 x 3words
while (counter < AudioGroups2Write*2) { /* 4:3 */
sample_number=(AudioGroupCounter*2)+ counter;
pack_AES_subframe(p, getChannelStatusBit(sample_number/2, 1),
- getZBit(sample_number/2), 0, audio_buffer_A[sample_number]); // left
+ getZBit(sample_number/2), 0, &audio_buffer_A[sample_number]); // left
p+=3; // step 3 words
sample_number=(AudioGroupCounter*2)+ counter+1;
pack_AES_subframe(p, getChannelStatusBit(sample_number/2, 2),
- getZBit(sample_number/2), 1, audio_buffer_A[sample_number]); // right
+ getZBit(sample_number/2), 1, &audio_buffer_A[sample_number]); // right
p+=3;
sample_number=(AudioGroupCounter*2)+ counter;
pack_AES_subframe(p, getChannelStatusBit(sample_number/2, 3),
- getZBit(sample_number/2), 2, audio_buffer_B[sample_number]); // left
+ getZBit(sample_number/2), 2, &audio_buffer_B[sample_number]); // left
p+=3;
sample_number=(AudioGroupCounter*2)+ counter+1;
pack_AES_subframe(p, getChannelStatusBit(sample_number/2, 4),
- getZBit(sample_number/2), 3, audio_buffer_B[sample_number]); // right
+ getZBit(sample_number/2), 3, &audio_buffer_B[sample_number]); // right
p+=3;
counter+=2;
}
// DC - DataCounter
cs += (*DID_pointer) & 0x1FF; // 9 x LSB
- // Wir merken uns die Adresse an der DC im Feld steht und addieren auf diese den tatsächlichen Wert von DC.
- // jetzt zeigt der merker auf das letzte Datenfeld...
-
+ // store address of DC an ad to the real value of DC
// DataCounter store
- // ´ende´ steht auf DataCounter
+ // ´ende´ point to DataCounter
uint16_t *ende = DID_pointer;
- // ´ende´ zeigt auf letztes feld
- ende += (*DID_pointer) & 0xFF; // ohne parity-Bit und ¬9-Bit
+ // ´ende´ point to last field
+ ende += (*DID_pointer) & 0xFF; // without parity-Bit and ¬9-Bit
DID_pointer++;
- // DID_pointer auf Adressen kleiner 'ende' zeigt
+ // while DID_pointer point to smaller addres like 'ende'
while (DID_pointer <= ende) {
cs += (*DID_pointer++) & 0x1FF; // 9 x LSB
}
- // limit to 9Bi
+ // limit to 9Bit, because of overflow of sum
cs = cs & 0x1FF;
- // bit10 NOT bit9
- // - cs invertieren (mit ~)
- // - & mit bitmaske '01 0000 0000'
- // - das übrig gebliebene Bit um eins nach links shiften
- // - auf cs addieren
+ // set bit10 NOT bit9:
+ // - cs invert
+ // - & with bitmask '01 0000 0000'
+ // - shift rest (1xbit)to left
+ // - add to cs
cs += ((~cs) & 0x100) << 1;
return cs;
} // end checker
-/** pack 16bit in AES subframe with 3words (30bit) and write in ´*p´
+/**
+ * pack 16bit in AES subframe with 3 words (30 bit) and write in ´*p´
* 10bit-words --> [X],[X+1], [X+2] implements 20bit for audio
*
* BIT 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
* @param z: value of AES subframe
* @param ch: channel od AES subframe (value:0,1,2,3)
* @param *audio_samplex: pointer to the audio buffer
- * */
-static int pack_AES_subframe(uint16_t *p, int8_t c, int8_t z, int8_t ch, int32_t audio_sample) {
+ **/
+static int pack_AES_subframe(uint16_t *p, int8_t c, int8_t z, int8_t ch, int16_t *audio_samplex) {
+
+ /**
+ * NOTE: WE JUST SUPPORT ONLY 16BIT SAMPLE SIZE
+ **/
// push 16bit up to 20bit(32bit)
- audio_sample <<= 4; // Shift by 4 (louder)
+ int32_t audio_sample = *audio_samplex;
+ audio_sample = audio_sample << 4; // Shift by 4 (louder)
// parity_counter
int8_t parity_counter = 0;
// 16bit buffer to write 10bit of [X]word,[X+1]word,[X+2]word,
uint16_t buffer = 0;
- // #########################################################
- // ### WORD X ############################################
- // #########################################################
+ //#########################################################
+ //### WORD X ############################################
+ //#########################################################
// word X: !bit8, a5, a4, a3, a2, a1, a0, ch1, ch0, z
// SMPTE 272M s.7
buffer = z; // z bit every 192bit = 1
// write word ´X´
*p++ = buffer;
- // count ones (zähle Einsen)
+ // count ones
int i = 0;
for (i = 0; i < 9; i++) {
if (buffer & 1 << i)
parity_counter++;
}
- // #########################################################
- // ### WORD X+1 ############################################
- // #########################################################
+ //#########################################################
+ //### WORD X+1 ############################################
+ //#########################################################
// word X+1: !bit8, a14, a13, a12, a11, a10, a9, a8, a7, a6
// SMPTE 272M s.7
buffer = 0;
parity_counter++;
}
- // #########################################################
- // ### WORD X+2 ############################################
- // #########################################################
+ //#########################################################
+ //### WORD X+2 ############################################
+ //#########################################################
// word X+2: !bit8, P, C, U, V, a19, a18, a17, a16, a15
// SMPTE 272M s.7
buffer = 0;
buffer += (audio_sample >> 15) & 0x01F; // a15 - a19
// default of [V][U][C] bits = `0`
- // buffer += 1<<5; // V (AES sample validity bit)
- // buffer += 1<<6; // U (AES user bit)
- // buffer += 1<<7; // C (AES audio channel status bit)
- buffer += c << 7; // C (AES audio channel status bit)
+ //buffer += 1<<5; // V (AES sample validity bit)
+ //buffer += 1<<6; // U (AES user bit)
+ //buffer += 1<<7; // C (AES audio channel status bit)
+ buffer += c << 7; // C (AES audio channel status bit)
- // count ones
+ // count ones (zähle Einsen)
for (i = 0; i < 8; i++) {
if (buffer & 1 << i)
parity_counter++;
}
- // if (!parity_counter%2) // else leave the 0
- // buffer+= 1 << 8; // P (AES even parity bit)
+ // if (!parity_counter%2) //else leave the 0
+ // buffer+= 1 << 8; // P (AES even parity bit)
//
- // buffer += ((~buffer) & 0x100 )<<1; // !bit8
- if ((parity_counter % 2) == 0) { // else leave the 0
+ // buffer += ((~buffer) & 0x100 )<<1; // !bit8
+ if ((parity_counter % 2) == 0) { //else leave the 0
buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
} else {
buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8
static uint8_t getZBit(int sample_number) {
// start in SDI line 6 also 18samples later
- // sample_number+=192-18;
+ //sample_number+=192-18;
if (sample_number % 192 == 0) {
- // printf("1 %i\n", sample_number);
+ //printf("1 %i\n", sample_number);
return 1;
} else {
- // printf("0");
+ //printf("0");
return 0;
}
}
uint8_t AESChannelStatusBit = 0;
// start in SDI line 6 also 18samples later
- // AESChannelStatusBit=((sample_number+192-18)%192);
+ //AESChannelStatusBit=((sample_number+192-18)%192);
// interval in 192bit
AESChannelStatusBit = sample_number % 192;
return 3;
}
- // // `4:3`-distribution
- // if(linenumber<=315){
- // if(linenumber>=6 && linenumber<=8){
- // return 0;
- // }
- // if((linenumber+5)%10==0){
- // return 4;
- // }else{
- // return 3;
- // }
- // }else{
- // if(linenumber>=319 && linenumber<=321){
- // return 0;
- // }
- // if((linenumber-8)%10==0){
- // return 4;
- // }else{
- // return 3;
- // }
- // }
-
- // // full-distribution
- // if(linenumber<=45){
- // return 4;
- // }else{
- // return 3;
- // }
-
- // // fullhalf-distribution
- // if (linenumber==625)
- // return 4;
+ // // `4:3`-distribution
+ // if(linenumber<=315){
+ // if(linenumber>=6 && linenumber<=8){
+ // return 0;
+ // }
+ // if((linenumber+5)%10==0){
+ // return 4;
+ // }else{
+ // return 3;
+ // }
+ // }else{
+ // if(linenumber>=319 && linenumber<=321){
+ // return 0;
+ // }
+ // if((linenumber-8)%10==0){
+ // return 4;
+ // }else{
+ // return 3;
+ // }
+ // }
+
+ // // full-distribution
+ // if(linenumber<=45){
+ // return 4;
+ // }else{
+ // return 3;
+ // }
+
+ // // fullhalf-distribution
+ // if (linenumber==625)
+ // return 4;
//
- // if (linenumber%14==0) {
- // return 4;
- // } else {
- // return 3;
- // }
+ // if (linenumber%14==0) {
+ // return 4;
+ // } else {
+ // return 3;
+ // }
}
static uint8_t getDBN(int my_DBN) {
return ((my_DBN - 1) % 255) + 1;
}
+/**
+ * pack8 - pack a line of 8-bit data
+ * @outbuf: pointer to the output buffer
+ * @inbuf: pointer to the input buffer
+ * @count: number of elements in the buffer
+ *
+ * Returns a pointer to the next output location.
+ **/
+static inline uint8_t *
+pack8(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
+ uint16_t *inp = inbuf;
+ uint8_t *outp = outbuf;
+
+ while (inp < (inbuf + count)) {
+ *outp++ = *inp++ >> 2;
+ }
+ return outp;
+}
/**
* pack10 - pack a line of 10-bit data
*
* Returns a pointer to the next output location.
**/
-static uint8_t * pack10(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
+static inline uint8_t * pack10(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
+
uint16_t *inp = inbuf;
uint8_t *outp = outbuf;
return outp;
}
+/**
+ * pack_v210 - pack a line of v210 data
+ * @outbuf: pointer to the output buffer
+ * @inbuf: pointer to the input buffer
+ * @count: number of elements in the buffer
+ *
+ * Returns a pointer to the next output location.
+ **/
+static inline uint8_t * pack_v210(uint8_t *outbuf, uint16_t *inbuf, size_t count) {
+
+ uint16_t *inp = inbuf;
+ uint8_t *outp = outbuf;
+
+ count = (count / 96) * 96 + ((count % 96) ? 96 : 0);
+ while (inp < (inbuf + count)) {
+ *outp++ = *inp & 0xff;
+ *outp = *inp++ >> 8;
+ *outp++ += (*inp << 2) & 0xfc;
+ *outp = *inp++ >> 6;
+ *outp++ += (*inp << 4) & 0xf0;
+ *outp++ = *inp++ >> 4;
+ }
+ return outp;
+}
// Clean up
static int sdimaster_close() {
- close(fh_sdi_dest);
+ free(line_buffer);
+ free(data);
+
+ if (fh_sdi_audio)
+ close(fh_sdi_audio);
+ if (fh_sdi_video)
+ close(fh_sdi_video);
return 1;
}
+
+/**
+ * mkline - generate one line
+ * @buf: pointer to a buffer
+ * @info: pointer to a line information structure
+ * @pattern: pattern
+ *
+ * Returns a negative error code on failure and zero on success.
+ **/
+static int mkline(unsigned short int *buf, const struct line_info *info, unsigned int pattern) {
+ const unsigned int b = 205;
+ unsigned short int *p = buf, *endp;
+ unsigned int samples = info->blanking ? info->fmt->samples_per_line : info->fmt->active_samples_per_line;
+
+ if (info->blanking) {
+ /* EAV */
+ *p++ = 0x3ff;
+ *p++ = 0x000;
+ *p++ = 0x000;
+ *p++ = info->xyz->eav;
+ /* Horizontal blanking */
+ while (p < (buf + 272)) {
+ *p++ = 0x200;
+ *p++ = 0x040;
+ *p++ = 0x200;
+ *p++ = 0x040;
+ }
+ /* SAV */
+ *p++ = 0x3ff;
+ *p++ = 0x000;
+ *p++ = 0x000;
+ *p++ = info->xyz->sav;
+ }
+ /* Active region */
+ endp = p;
+ switch (pattern) {
+ default:
+ case VERT_BLANKING:
+ while (p < (buf + samples)) {
+ *p++ = 0x200;
+ *p++ = 0x040;
+ *p++ = 0x200;
+ *p++ = 0x040;
+ }
+ break;
+ case BLACK:
+ while (p < (buf + samples)) {
+ *p++ = 0x200;
+ *p++ = 0x040;
+ *p++ = 0x200;
+ *p++ = 0x040;
+ }
+ break;
+ case MAIN_SET:
+ /* 75% gray */
+ endp += b + 1;
+ while (p < endp) {
+ *p++ = 512;
+ *p++ = 721;
+ *p++ = 512;
+ *p++ = 721;
+ }
+ /* 75% yellow */
+ endp += b + 1;
+ while (p < endp) {
+ *p++ = 176;
+ *p++ = 646;
+ *p++ = 567;
+ *p++ = 646;
+ }
+ /* 75% cyan */
+ endp += b + 1;
+ while (p < endp) {
+ *p++ = 625;
+ *p++ = 525;
+ *p++ = 176;
+ *p++ = 525;
+ }
+ /* 75% green */
+ endp += b - 1;
+ while (p < endp) {
+ *p++ = 289;
+ *p++ = 450;
+ *p++ = 231;
+ *p++ = 450;
+ }
+ /* 75% magenta */
+ endp += b + 1;
+ while (p < endp) {
+ *p++ = 735;
+ *p++ = 335;
+ *p++ = 793;
+ *p++ = 335;
+ }
+ /* 75% red */
+ endp += b + 1;
+ while (p < endp) {
+ *p++ = 399;
+ *p++ = 260;
+ *p++ = 848;
+ *p++ = 260;
+ }
+ /* 75% blue */
+ while (p < (buf + samples)) {
+ *p++ = 848;
+ *p++ = 139;
+ *p++ = 457;
+ *p++ = 139;
+ }
+ break;
+ case CHROMA_SET:
+ /* 75% blue */
+ endp += b + 1;
+ while (p < endp) {
+ *p++ = 848;
+ *p++ = 139;
+ *p++ = 457;
+ *p++ = 139;
+ }
+ /* black */
+ endp += b + 1;
+ while (p < endp) {
+ *p++ = 0x200;
+ *p++ = 0x040;
+ *p++ = 0x200;
+ *p++ = 0x040;
+ }
+ /* 75% magenta */
+ endp += b + 1;
+ while (p < endp) {
+ *p++ = 735;
+ *p++ = 335;
+ *p++ = 793;
+ *p++ = 335;
+ }
+ /* black */
+ endp += b - 1;
+ while (p < endp) {
+ *p++ = 0x200;
+ *p++ = 0x040;
+ *p++ = 0x200;
+ *p++ = 0x040;
+ }
+ /* 75% cyan */
+ endp += b + 1;
+ while (p < endp) {
+ *p++ = 625;
+ *p++ = 525;
+ *p++ = 176;
+ *p++ = 525;
+ }
+ /* black */
+ endp += b + 1;
+ while (p < endp) {
+ *p++ = 0x200;
+ *p++ = 0x040;
+ *p++ = 0x200;
+ *p++ = 0x040;
+ }
+ /* 75% gray */
+ while (p < (buf + samples)) {
+ *p++ = 512;
+ *p++ = 721;
+ *p++ = 512;
+ *p++ = 721;
+ }
+ break;
+ case BLACK_SET:
+ /* -I */
+ endp += 257;
+ while (p < endp) {
+ *p++ = 624;
+ *p++ = 231;
+ *p++ = 390;
+ *p++ = 231;
+ }
+ /* white */
+ endp += 257;
+ while (p < endp) {
+ *p++ = 0x200;
+ *p++ = 940;
+ *p++ = 0x200;
+ *p++ = 940;
+ }
+ /* +Q */
+ endp += 257;
+ while (p < endp) {
+ *p++ = 684;
+ *p++ = 177;
+ *p++ = 591;
+ *p++ = 177;
+ }
+ /* black */
+ endp += 257;
+ while (p < endp) {
+ *p++ = 0x200;
+ *p++ = 0x040;
+ *p++ = 0x200;
+ *p++ = 0x040;
+ }
+ /* blacker than black */
+ endp += 68;
+ while (p < endp) {
+ *p++ = 0x200;
+ *p++ = 29;
+ *p++ = 0x200;
+ *p++ = 29;
+ }
+ /* black */
+ endp += 68 + 2;
+ while (p < endp) {
+ *p++ = 0x200;
+ *p++ = 0x040;
+ *p++ = 0x200;
+ *p++ = 0x040;
+ }
+ /* whiter than black */
+ endp += 68;
+ while (p < endp) {
+ *p++ = 0x200;
+ *p++ = 99;
+ *p++ = 0x200;
+ *p++ = 99;
+ }
+ /* black */
+ while (p < (buf + samples)) {
+ *p++ = 0x200;
+ *p++ = 0x040;
+ *p++ = 0x200;
+ *p++ = 0x040;
+ }
+ break;
+ }
+ return 0;
+}