* 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
+ * SD NTSC 720 × 486/59.94/I interlaced 30000/1001 ~ 29.97 HZ 8 x AES (16 channels) sdi_486i_5994 TODO:180,145,159,107
+ * SD NTSC 720 × 486/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_profile.h>
#include <framework/mlt_log.h>
+#include <framework/mlt_events.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdint.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#ifdef WITH_JPEG
// for JPEG output
int height;
struct audio_format audio_format;
- /** device file:
+ /**
+ * 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:
+ /**
+ * 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
- char *video_fmt_name; // 1080i25, 1080p25, 576i50, 480i2997, ...
+ char *video_fmt_name; // 1080i25, 1080p25, 576i50, 486i2997, ...
};
static void *consumer_thread(void *);
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);
+int convertYCBCRtoRGB(int y1, int cb, int cr, int y2, uint8_t * target_rgb);
/*****************************************************************************************************
****************************************** SDI Master Consumer **************************************
mlt_consumer consumer_SDIstream_init(mlt_profile profile, mlt_service_type type, const char *id, char *arg) {
// Create the consumer object
- consumer_SDIstream this = calloc(sizeof(struct consumer_SDIstream_s), 1);
+ consumer_SDIstream this = calloc( 1, sizeof(struct consumer_SDIstream_s) );
// If malloc and consumer init ok
if (this != NULL && mlt_consumer_init(&this->parent, this, profile) == 0) {
parent->stop = consumer_stop;
parent->is_stopped = consumer_is_stopped;
- // Set explizit to zero or other value
+ // Set explicit 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;
}
}
+
+ mlt_events_register( MLT_CONSUMER_PROPERTIES(parent), "consumer-fatal-error", NULL );
// Return the consumer produced
return parent;
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"));
}
}
- // Define a frame pointer
- mlt_frame frame;
+ // Set additional device file defaults
+ struct stat st;
+ int fd = -1;
+ if (this->device_file_video)
+ fd = stat(this->device_file_video, &st);
+ if (fd == -1) {
+ if (this->device_file_video)
+ free(this->device_file_video);
+ this->device_file_video = strdup("/dev/sdivideotx0");
+ } else {
+ close(fd);
+ }
+ if (this->device_file_audio) {
+ fd = stat(this->device_file_audio, &st);
+ if (fd == -1) {
+ if (this->device_file_audio)
+ free(this->device_file_audio);
+ this->device_file_audio = strdup("/dev/sdiaudiotx0");
+ } else {
+ close(fd);
+ }
+ } else if (this->device_file_video &&
+ strstr(this->device_file_video, "sdivideotx")) {
+ if (this->device_file_audio)
+ free(this->device_file_audio);
+ this->device_file_audio = strdup("/dev/sdiaudiotx0");
+ }
- if (!sdi_init(this->device_file_video, this->device_file_audio, this->blanking, mlt_service_profile((mlt_service) consumer))) {
- exit(0);
+ // 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")) {
+ // set value
+ if (!strcmp( mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "blanking"), "false")) {
+ this->blanking = 0;
+ } else if (!strcmp( mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "blanking"), "true")) {
+ this->blanking = 1;
+ } else {
+ this->blanking = mlt_properties_get_int(MLT_CONSUMER_PROPERTIES( consumer ), "blanking");
+ }
+ } else if (this->device_file_video && strstr(this->device_file_video, "sdivideotx")) {
+ this->blanking = 0;
+ } else {
+ // set default value without HD board, also with blanking
+ this->blanking = 1;
}
+ // Define a frame pointer
+ mlt_frame frame;
+
// set Datablock number for SDI encoding
int my_dbn = 1;
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;
+ int frequency = this->audio_format.sample_rate;
+ int channels = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES(consumer), "channels" );
+ int samples;
+
+ // set number of audio channels, linsys vidport model 193 is limited to 8 channels (4AES frames)
+ this->audio_format.channels = 8; /* 0,2,4,6,8 */
+ this->audio_format.aformat = mlt_audio_s16; /* 16, 24, 32 */
+ this->audio_format.sample_rate = 48000;
this->pix_fmt = mlt_image_yuv422;
+ if (this->device_file_video && this->device_file_audio &&
+ !sdi_init(this->device_file_video, this->device_file_audio, this->blanking, mlt_service_profile((mlt_service) consumer), &this->audio_format)) {
+ mlt_log_fatal( MLT_CONSUMER_SERVICE(consumer), "failed to initialize\n" );
+ mlt_events_fire( MLT_CONSUMER_PROPERTIES(consumer), "consumer-fatal-error", NULL );
+ }
+
uint8_t *video_buffer;
int16_t *audio_buffer_tmp; // the upstream audio buffer
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
+ samples = mlt_sample_calculator(fps, frequency, count++);
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
+ /* TODO: Audio is currently hard coded to 8 channels because write 8 channels to the sdi board.
+ The Linys SDI board has to be configured with the same number of channels!
+ 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
} else if (save_jpegs > 0) {
counter++;
}
+ mlt_events_fire(MLT_CONSUMER_PROPERTIES( consumer ), "consumer-frame-show", frame, NULL );
} else {
mlt_log_warning(MLT_CONSUMER_SERVICE(consumer), "Videobuffer was NULL, skipping playout!\n");
}
* @param target pointer
* @return 0 upon success
**/
-int convertYCBCRtoRGB(int y1, int cb, int cr, int y2, int * target_rgb) {
+int convertYCBCRtoRGB(int y1, int cb, int cr, int y2, uint8_t * target_rgb) {
#ifdef WITH_JPEG
- uint32_t tmp = 0;
+ if(y1 > 235)
+ y1 = 235;
+ if(y1 < 16)
+ y1 = 16;
+
+ if(y2 > 235)
+ y2 = 235;
+ if(y2 < 16)
+ y2 = 16;
+
+ if(cr > 240)
+ cr = 240;
+ if(cr < 16)
+ cr = 16;
+
+ if(cb > 240)
+ cb = 240;
+ if(cb < 16)
+ cb = 16;
+
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;
+ r1 = y1 + 1.402 * (cr - 128);
+ g1 = y1 - 0.34414 * (cb - 128) - 0.71414 * (cr - 128);
+ b1 = y1 + 1.772 * (cb - 128);
+
+ r2 = y2 + 1.402 * (cr - 128);
+ g2 = y2 - 0.34414 * (cb - 128) - 0.71414 *(cr - 128);
+ b2 = y2 + 1.772 * (cb - 128);
*target_pointer++ = r1;
*target_pointer++ = g1;