Browse files

update encoder API for 12M-1999

BGF assignment according to TV standard.
non backwards compatible API change.
  • Loading branch information...
1 parent 959c8df commit 49c005302fa733b6b50161ce9600a2b94c3e524d @x42 committed Nov 17, 2012
Showing with 169 additions and 75 deletions.
  1. +2 −1 src/encoder.h
  2. +49 −21 src/ltc.c
  3. +73 −22 src/ltc.h
  4. +40 −28 src/timecode.c
  5. +2 −1 tests/example_encode.c
  6. +3 −2 tests/ltcencode.c
View
3 src/encoder.h
@@ -27,7 +27,8 @@ struct LTCEncoder {
double fps;
double sample_rate;
double filter_const;
- int use_date;
+ int flags;
+ enum LTC_TV_STANDARD standard;
ltcsnd_sample_t enc_lo, enc_hi;
size_t offset;
View
70 src/ltc.c
@@ -112,7 +112,7 @@ int ltc_decoder_queue_length(LTCDecoder* d) {
* Encoder
*/
-LTCEncoder* ltc_encoder_create(double sample_rate, double fps, int use_date) {
+LTCEncoder* ltc_encoder_create(double sample_rate, double fps, enum LTC_TV_STANDARD standard, int flags) {
if (sample_rate < 1)
return NULL;
@@ -131,17 +131,8 @@ LTCEncoder* ltc_encoder_create(double sample_rate, double fps, int use_date) {
return NULL;
}
- e->sample_rate = sample_rate;
- ltc_encoder_set_filter(e, 40.0);
- e->fps = fps;
- e->use_date = use_date;
- e->samples_per_clock = sample_rate / (fps * 80.0);
- e->samples_per_clock_2 = e->samples_per_clock / 2.0;
- e->sample_remainder = 0.5;
ltc_frame_reset(&e->f);
-
- if (rint(fps*100) == 2997)
- e->f.dfbit = 1;
+ ltc_encoder_reinit(e, sample_rate, fps, standard, flags);
return e;
}
@@ -151,7 +142,7 @@ void ltc_encoder_free(LTCEncoder *e) {
free(e);
}
-int ltc_encoder_reinit(LTCEncoder *e, double sample_rate, double fps, int use_date) {
+int ltc_encoder_reinit(LTCEncoder *e, double sample_rate, double fps, enum LTC_TV_STANDARD standard, int flags) {
if (sample_rate < 1)
return -1;
@@ -165,13 +156,38 @@ int ltc_encoder_reinit(LTCEncoder *e, double sample_rate, double fps, int use_da
e->sample_rate = sample_rate;
ltc_encoder_set_filter(e, 40.0);
e->fps = fps;
- e->use_date = use_date;
+ e->flags = flags;
+ e->standard = standard;
e->samples_per_clock = sample_rate / (fps * 80.0);
e->samples_per_clock_2 = e->samples_per_clock / 2.0;
e->sample_remainder = 0.5;
+ if (flags & LTC_BGF_DONT_TOUCH) {
+ e->f.col_frame = 0;
+ if (flags&LTC_TC_CLOCK) {
+ e->f.binary_group_flag_bit1 = 1;
+ } else {
+ e->f.binary_group_flag_bit1 = 0;
+ }
+ switch (standard) {
+ case LTC_TV_625_50: /* 25 fps mode */
+ e->f.biphase_mark_phase_correction = 0; // BGF0
+ e->f.binary_group_flag_bit0 = (flags&LTC_USE_DATE)?1:0; // BGF2
+ break;
+ default:
+ e->f.binary_group_flag_bit0 = 0;
+ e->f.binary_group_flag_bit2 = (flags&LTC_USE_DATE)?1:0;
+ break;
+ }
+ }
+ if ((flags&LTC_NO_PARITY) == 0) {
+ ltc_frame_set_parity(&e->f, standard);
+ }
+
if (rint(fps*100) == 2997)
e->f.dfbit = 1;
+ else
+ e->f.dfbit = 0;
return 0;
}
@@ -231,11 +247,11 @@ void ltc_encoder_encode_frame(LTCEncoder *e) {
}
void ltc_encoder_get_timecode(LTCEncoder *e, SMPTETimecode *t) {
- ltc_frame_to_time(t, &e->f, e->use_date);
+ ltc_frame_to_time(t, &e->f, e->flags);
}
void ltc_encoder_set_timecode(LTCEncoder *e, SMPTETimecode *t) {
- ltc_time_to_frame(&e->f, t, e->use_date);
+ ltc_time_to_frame(&e->f, t, e->standard, e->flags);
}
void ltc_encoder_get_frame(LTCEncoder *e, LTCFrame *f) {
@@ -247,11 +263,11 @@ void ltc_encoder_set_frame(LTCEncoder *e, LTCFrame *f) {
}
int ltc_encoder_inc_timecode(LTCEncoder *e) {
- return ltc_frame_increment (&e->f, rint(e->fps), e->use_date);
+ return ltc_frame_increment (&e->f, rint(e->fps), e->standard, e->flags);
}
int ltc_encoder_dec_timecode(LTCEncoder *e) {
- return ltc_frame_decrement (&e->f, rint(e->fps), e->use_date);
+ return ltc_frame_decrement (&e->f, rint(e->fps), e->standard, e->flags);
}
size_t ltc_encoder_get_buffersize(LTCEncoder *e) {
@@ -275,14 +291,26 @@ int ltc_encoder_get_buffer(LTCEncoder *e, ltcsnd_sample_t *buf) {
return(len);
}
-void ltc_frame_set_parity(LTCFrame *frame) {
+void ltc_frame_set_parity(LTCFrame *frame, enum LTC_TV_STANDARD standard) {
int i;
unsigned char p = 0;
- frame->biphase_mark_phase_correction = 0;
+
+ if (standard != LTC_TV_625_50) { /* 30fps, 24fps */
+ frame->biphase_mark_phase_correction = 0;
+ } else { /* 25fps */
+ frame->binary_group_flag_bit2 = 0;
+ }
+
for (i=0; i < LTC_FRAME_BIT_COUNT / 8; ++i){
p = p ^ (((unsigned char*)frame)[i]);
}
#define PRY(BIT) ((p>>BIT)&1)
- frame->biphase_mark_phase_correction =
- PRY(0)^PRY(1)^PRY(2)^PRY(3)^PRY(4)^PRY(5)^PRY(6)^PRY(7);
+
+ if (standard != LTC_TV_625_50) { /* 30fps, 24fps */
+ frame->biphase_mark_phase_correction =
+ PRY(0)^PRY(1)^PRY(2)^PRY(3)^PRY(4)^PRY(5)^PRY(6)^PRY(7);
+ } else { /* 25fps */
+ frame->binary_group_flag_bit2 =
+ PRY(0)^PRY(1)^PRY(2)^PRY(3)^PRY(4)^PRY(5)^PRY(6)^PRY(7);
+ }
}
View
95 src/ltc.h
@@ -231,6 +231,25 @@ struct LTCFrame {
};
#endif
+/** the standard defines the assignment of the binary-group-flag bits
+ * basically only 25fps is different, but other standards defined in
+ * the SMPTE spec have been included for completeness.
+ */
+enum LTC_TV_STANDARD {
+ LTC_TV_525_60, ///< 30fps
+ LTC_TV_625_50, ///< 25fps
+ LTC_TV_1125_60,///< 30fps
+ LTC_TV_FILM_24 ///< 24fps
+};
+
+/** encoder and LTCframe <> timecode operation flags */
+enum LTC_BG_FLAGS {
+ LTC_USE_DATE = 1, ///< LTCFrame <> SMPTETimecode converter and LTCFrame increment/decrement use date, also set BGF2 to '1' when encoder is initialized or re-initialized (unless LTC_BGF_DONT_TOUCH is given)
+ LTC_TC_CLOCK = 2,///< the Timecode is wall-clock aka freerun. This also sets BGF1 (unless LTC_BGF_DONT_TOUCH is given)
+ LTC_BGF_DONT_TOUCH = 4, ///< encoder init or re-init does not touch the BGF bits (initial values after initialization is zero)
+ LTC_NO_PARITY = 8 ///< parity bit is left untouched when setting or in/decrementing the encoder frame-number
+};
+
/**
* see LTCFrame
*/
@@ -306,23 +325,25 @@ typedef struct LTCEncoder LTCEncoder;
*
* @param stime output
* @param frame input
- * @param set_flags if > 0 the user-fields in LTCFrame will be parsed into the date variable of SMPTETimecode.
- * If < 0 all date fields are reset to zero.
- * if set_flags is zero, all the date and timezone is not touched.
+ * @param flags binary combination of \ref LTC_BG_FLAGS - here only LTC_USE_DATE is relevant.
+ * if LTC_USE_DATE is set, the user-fields in LTCFrame will be parsed into the date variable of SMPTETimecode.
+ * otherwise the date information in the SMPTETimecode is set to zero.
*/
-void ltc_frame_to_time(SMPTETimecode* stime, LTCFrame* frame, int set_flags);
+void ltc_frame_to_time(SMPTETimecode* stime, LTCFrame* frame, int flags);
/**
* Translate SMPTETimecode struct into its binary LTC representation
* and set the LTC frame's parity bit accordingly (see \ref ltc_frame_set_parity)
*
* @param frame output - the frame to be set
* @param stime input - timecode input
- * @param set_flags if > 0 the user-fields in LTCFrame will be set from the date in SMPTETimecode,
- * if < 0 the user-fields will be set to zero. If > 1 or < -1 the binary_group_flag and color-frame flag are reset to zero.
- * if set_flags is zero, all non-timecode fields remain untouched.
+ * @param standard the TV standard to use for parity bit assignment
+ * @param flags binary combination of \ref LTC_BG_FLAGS - here only LTC_USE_DATE and LTC_NO_PARITY are relevant.
+ * if LTC_USE_DATE is given, user-fields in LTCFrame will be set from the date in SMPTETimecode,
+ * otherwise the user-bits are not modified. All non-timecode fields remain untouched - except for the parity bit
+ * unless LTC_NO_PARITY is given.
*/
-void ltc_time_to_frame(LTCFrame* frame, SMPTETimecode* stime, int set_flags);
+void ltc_time_to_frame(LTCFrame* frame, SMPTETimecode* stime, enum LTC_TV_STANDARD standard, int flags);
/**
* Reset all values of a LTC FRAME to zero, except for the sync-word (0x3FFD) at the end.
@@ -338,25 +359,32 @@ void ltc_frame_reset(LTCFrame* frame);
*
* @param frame the LTC-timecode to increment
* @param fps integer framerate (for drop-frame-timecode set frame->dfbit and round-up the fps).
- * @param use_date interpret user-data as date and increment date if timecode wraps after 24h.
+ * @param standard the TV standard to use for parity bit assignment
+ * if set to 1 the 25fps standard is enabled and LTC Frame bit 59 instead of 27 is used for the parity. It only has only has effect flag bit 4 (LTC_NO_PARITY) is cleared.
+ * @param flags binary combination of \ref LTC_BG_FLAGS - here only LTC_USE_DATE and LTC_NO_PARITY are relevant.
+ * If the bit 0 (1) is set (1) interpret user-data as date and increment date if timecode wraps after 24h.
* (Note: leap-years are taken into account, but since the year is two-digit only, the 100,400yr rules are ignored.
* "00" is assumed to be year 2000 which was a leap year.)
* @return 1 if timecode was wrapped around after 23:59:59:ff, 0 otherwise
*/
-int ltc_frame_increment(LTCFrame *frame, int fps, int use_date);
+int ltc_frame_increment(LTCFrame* frame, int fps, enum LTC_TV_STANDARD standard, int flags);
/**
* Decrement the timecode by one Frame (1/framerate seconds)
* and set the Frame's parity bit accordingly (see \ref ltc_frame_set_parity)
*
* @param frame the LTC-timecode to decrement
* @param fps integer framerate (for drop-frame-timecode set frame->dfbit and round-up the fps).
- * @param use_date interpret user-data as date and decrement date if timecode wraps at 24h.
+ * @param standard the TV standard to use for parity bit assignment
+ * if set to 1 the 25fps standard is enabled and LTC Frame bit 59 instead of 27 is used for the parity. It only has only has effect flag bit 4 (LTC_NO_PARITY) is cleared.
+ * @param flags binary combination of \ref LTC_BG_FLAGS - here only LTC_USE_DATE and LTC_NO_PARITY are relevant.
+ * if the bit 0 is set (1) interpret user-data as date and decrement date if timecode wraps at 24h.
* (Note: leap-years are taken into account, but since the year is two-digit only, the 100,400yr rules are ignored.
* "00" is assumed to be year 2000 which was a leap year.)
+ * bit 3 (8) indicates that the parity bit should not be touched
* @return 1 if timecode was wrapped around at 23:59:59:ff, 0 otherwise
*/
-int ltc_frame_decrement(LTCFrame* frame, int fps, int use_date);
+int ltc_frame_decrement(LTCFrame* frame, int fps, enum LTC_TV_STANDARD standard, int flags);
/**
* Create a new LTC decoder.
@@ -451,14 +479,14 @@ int ltc_decoder_queue_length(LTCDecoder* d);
/**
* Allocate and initialize LTC audio encoder.
*
- * Note: if fps equals to 29.97 or 30000.0/1001.0, the LTCFrame's 'dfbit' bit is set to 1
- * to indicate drop-frame timecode.
+ * calls \ref ltc_encoder_reinit internally see, see notes there.
*
* @param sample_rate audio sample rate (eg. 48000)
* @param fps video-frames per second (e.g. 25.0)
- * @param use_date use LTC-user-data for date
+ * @param standard the TV standard to use for Binary Group Flag bit position
+ * @param flags binary combination of \ref LTC_BG_FLAGS
*/
-LTCEncoder * ltc_encoder_create(double sample_rate, double fps, int use_date);
+LTCEncoder* ltc_encoder_create(double sample_rate, double fps, enum LTC_TV_STANDARD standard, int flags);
/**
* Release memory of the encoder.
@@ -577,12 +605,22 @@ size_t ltc_encoder_get_buffersize(LTCEncoder *e);
* prepare an internal buffer large enough to accommodate all
* sample_rate, fps combinations that you would like to re-init to.
*
+ * The LTC frame payload data is not modified by this call, however,
+ * the flag-bits of the LTC-Frame are updated:
+ * If fps equals to 29.97 or 30000.0/1001.0, the LTCFrame's 'dfbit' bit is set to 1
+ * to indicate drop-frame timecode.
+ *
+ * Unless the LTC_BGF_DONT_TOUCH flag is set the BGF1 is set or cleared depending
+ * on LTC_TC_CLOCK and BGF0,2 according to LTC_USE_DATE and the given standard.
+ * col_frame is cleared and the parity recomputed (unless LTC_NO_PARITY is given).
+ *
* @param e encoder handle
* @param sample_rate audio sample rate (eg. 48000)
* @param fps video-frames per second (e.g. 25.0)
- * @param use_date use LTC-user-data for date
+ * @param standard the TV standard to use for Binary Group Flag bit position
+ * @param flags binary combination of \ref LTC_BG_FLAGS
*/
-int ltc_encoder_reinit(LTCEncoder *e, double sample_rate, double fps, int use_date);
+int ltc_encoder_reinit(LTCEncoder *e, double sample_rate, double fps, enum LTC_TV_STANDARD standard, int flags);
/**
* reset ecoder state.
@@ -676,8 +714,8 @@ int ltc_encoder_encode_byte(LTCEncoder *e, int byte, double speed);
* This is equivalent to calling \ref ltc_encoder_encode_byte 10 times for
* bytes 0..9 with speed 1.0.
*
- * Note: The internal buffer must be empty before calling this function.
- * Otherwise it may overflow. This is usually the case if it is read with
+ * Note: The internal buffer must be empty before calling this function.
+ * Otherwise it may overflow. This is usually the case if it is read with
* \ref ltc_encoder_get_buffer after calling this function.
*
* The default internal buffersize is exactly one full LTC frame at speed 1.0.
@@ -689,7 +727,7 @@ void ltc_encoder_encode_frame(LTCEncoder *e);
/**
* Set the parity of the LTC frame.
*
- * Bi-Phase Mark Phase Correction bit (bit 27) may be set or cleared so that
+ * Bi-Phase Mark Phase Correction bit (bit 27 - or 59) may be set or cleared so that
* that every 80-bit word contains an even number of zeroes.
* This means that the phase in every Sync Word will be the same.
*
@@ -701,8 +739,21 @@ void ltc_encoder_encode_frame(LTCEncoder *e);
* \ref ltc_frame_decrement include a call to it.
*
* @param frame the LTC to analyze and set or clear the biphase_mark_phase_correction bit.
+ * @param standard If 1 (aka LTC_TV_625_50) , the 25fps mode (bit 59 - aka binary_group_flag_bit2) is used, otherwise the 30fps, 24fps mode (bit 27 -- biphase_mark_phase_correction) is set or cleared.
+ */
+void ltc_frame_set_parity(LTCFrame *frame, enum LTC_TV_STANDARD standard);
+
+/**
+ * Parse Binary Group Flags into standard independent format:
+ * bit 0 (1) - BGF 0,
+ * bit 1 (2) - BGF 1,
+ * bit 2 (4) - BGF 2
+ *
+ * @param f LTC frame data analyze
+ * @param standard the TV standard to use -- see \ref LTCFrame for BGF assignment
+ * @return LTC Binary Group Flags
*/
-void ltc_frame_set_parity(LTCFrame *frame);
+int parse_bcg_flags(LTCFrame *f, enum LTC_TV_STANDARD standard);
#ifdef __cplusplus
}
View
68 src/timecode.c
@@ -161,16 +161,16 @@ static void skip_drop_frames(LTCFrame* frame) {
}
}
-void ltc_frame_to_time(SMPTETimecode *stime, LTCFrame *frame, int set_flags) {
+void ltc_frame_to_time(SMPTETimecode *stime, LTCFrame *frame, int flags) {
if (!stime) return;
- if (set_flags > 0) {
+ if (flags & LTC_USE_DATE) {
smpte_set_timezone_string(frame, stime);
stime->years = frame->user5 + frame->user6*10;
stime->months = frame->user3 + frame->user4*10;
stime->days = frame->user1 + frame->user2*10;
- } else if (set_flags < 0) {
+ } else {
stime->years = 0;
stime->months = 0;
stime->days = 0;
@@ -183,29 +183,15 @@ void ltc_frame_to_time(SMPTETimecode *stime, LTCFrame *frame, int set_flags) {
stime->frame = frame->frame_units + frame->frame_tens*10;
}
-void ltc_time_to_frame(LTCFrame* frame, SMPTETimecode* stime, int set_flags) {
- if (set_flags > 0) {
+void ltc_time_to_frame(LTCFrame* frame, SMPTETimecode* stime, enum LTC_TV_STANDARD standard, int flags) {
+ if (flags & LTC_USE_DATE) {
smpte_set_timezone_code(stime, frame);
frame->user6 = stime->years/10;
frame->user5 = stime->years - frame->user6*10;
frame->user4 = stime->months/10;
frame->user3 = stime->months - frame->user4*10;
frame->user2 = stime->days/10;
frame->user1 = stime->days - frame->user2*10;
- } else if (set_flags < 0) {
- frame->user8 = 0;
- frame->user7 = 0;
- frame->user6 = 0;
- frame->user5 = 0;
- frame->user4 = 0;
- frame->user3 = 0;
- frame->user2 = 0;
- frame->user1 = 0;
- }
- if (abs(set_flags) > 1) {
- frame->binary_group_flag_bit1 = 0;
- frame->binary_group_flag_bit2 = 0;
- frame->col_frame = 0; // colour
}
frame->hours_tens = stime->hours/10;
@@ -222,7 +208,9 @@ void ltc_time_to_frame(LTCFrame* frame, SMPTETimecode* stime, int set_flags) {
skip_drop_frames(frame);
}
- ltc_frame_set_parity(frame);
+ if ((flags & LTC_NO_PARITY) == 0) {
+ ltc_frame_set_parity(frame, standard);
+ }
}
void ltc_frame_reset(LTCFrame* frame) {
@@ -237,7 +225,7 @@ void ltc_frame_reset(LTCFrame* frame) {
#endif
}
-int ltc_frame_increment(LTCFrame* frame, int fps, int use_date) {
+int ltc_frame_increment(LTCFrame* frame, int fps, enum LTC_TV_STANDARD standard, int flags) {
int rv = 0;
frame->frame_units++;
@@ -280,7 +268,7 @@ int ltc_frame_increment(LTCFrame* frame, int fps, int use_date) {
frame->hours_tens=0;
frame->hours_units = 0;
- if (use_date)
+ if (flags&1)
{
/* wrap date */
SMPTETimecode stime;
@@ -328,11 +316,14 @@ int ltc_frame_increment(LTCFrame* frame, int fps, int use_date) {
skip_drop_frames(frame);
}
- ltc_frame_set_parity(frame);
+ if ((flags & LTC_NO_PARITY) == 0) {
+ ltc_frame_set_parity(frame, standard);
+ }
return rv;
}
-int ltc_frame_decrement(LTCFrame* frame, int fps, int use_date) {
+
+int ltc_frame_decrement(LTCFrame* frame, int fps, enum LTC_TV_STANDARD standard, int flags) {
int rv = 0;
int frames = frame->frame_units + frame->frame_tens * 10;
@@ -378,7 +369,7 @@ int ltc_frame_decrement(LTCFrame* frame, int fps, int use_date) {
if (hours == 23) {
/* 24h wrap around */
rv=1;
- if (use_date)
+ if (flags&LTC_USE_DATE)
{
/* wrap date */
SMPTETimecode stime;
@@ -428,12 +419,33 @@ int ltc_frame_decrement(LTCFrame* frame, int fps, int use_date) {
&& (frame->frame_units == 1)
&& (frame->frame_tens == 0)
) {
- ltc_frame_decrement(frame, fps, use_date);
- ltc_frame_decrement(frame, fps, use_date);
+ ltc_frame_decrement(frame, fps, standard, flags&LTC_USE_DATE);
+ ltc_frame_decrement(frame, fps, standard, flags&LTC_USE_DATE);
}
}
- ltc_frame_set_parity(frame);
+ if ((flags & LTC_NO_PARITY) == 0) {
+ ltc_frame_set_parity(frame, standard);
+ }
return rv;
}
+
+int parse_bcg_flags(LTCFrame *f, enum LTC_TV_STANDARD standard) {
+ switch (standard) {
+ case LTC_TV_625_50: /* 25 fps mode */
+ return (
+ ((f->binary_group_flag_bit0)?4:0)
+ | ((f->binary_group_flag_bit1)?2:0)
+ | ((f->biphase_mark_phase_correction)?1:0)
+ );
+ break;
+ default: /* 24,30 fps mode */
+ return (
+ ((f->binary_group_flag_bit2)?4:0)
+ | ((f->binary_group_flag_bit1)?2:0)
+ | ((f->binary_group_flag_bit0)?1:0)
+ );
+ break;
+ }
+}
View
3 tests/example_encode.c
@@ -99,7 +99,8 @@ int main(int argc, char **argv) {
}
/* prepare encoder */
- encoder = ltc_encoder_create(sample_rate, fps, 1);
+ encoder = ltc_encoder_create(sample_rate, fps,
+ fps==25?LTC_TV_625_50:LTC_TV_525_60, LTC_USE_DATE);
ltc_encoder_set_timecode(encoder, &st);
#ifdef USE_LOCAL_BUFFER
View
5 tests/ltcencode.c
@@ -81,9 +81,10 @@ int main(int argc, char **argv) {
return 1;
}
- encoder = ltc_encoder_create(1, 1, 1);
+ encoder = ltc_encoder_create(1, 1, 0, LTC_USE_DATE);
ltc_encoder_set_bufsize(encoder, sampleRate, fps);
- ltc_encoder_reinit(encoder, sampleRate, fps, 1);
+ ltc_encoder_reinit(encoder, sampleRate, fps,
+ fps==25?LTC_TV_625_50:LTC_TV_525_60, LTC_USE_DATE);
ltc_encoder_set_filter(encoder, 0);
ltc_encoder_set_filter(encoder, 25.0);

0 comments on commit 49c0053

Please sign in to comment.