/* FIXME: for our purposes it's probably enough to just check for the sync * marker - we just want to know if it's a header frame or not */ static gboolean gst_flac_dec_scan_got_frame (GstFlacDec * flacdec, guint8 * data, guint size, gint64 * last_sample_num) { guint headerlen; guint sr_from_end = 0; /* can be 0, 8 or 16 */ guint bs_from_end = 0; /* can be 0, 8 or 16 */ guint32 val = 0; guint8 bs, sr, ca, ss, pb; if (size < 10) return FALSE; /* sync */ if (data[0] != 0xFF || (data[1] & 0xFC) != 0xF8) return FALSE; if (data[1] & 1) { GST_WARNING_OBJECT (flacdec, "Variable block size FLAC unsupported"); return FALSE; } bs = (data[2] & 0xF0) >> 4; /* blocksize marker */ sr = (data[2] & 0x0F); /* samplerate marker */ ca = (data[3] & 0xF0) >> 4; /* channel assignment */ ss = (data[3] & 0x0F) >> 1; /* sample size marker */ pb = (data[3] & 0x01); /* padding bit */ GST_LOG_OBJECT (flacdec, "got sync, bs=%x,sr=%x,ca=%x,ss=%x,pb=%x", bs, sr, ca, ss, pb); if (bs == 0 || sr == 0x0F || ca >= 0x0B || ss == 0x03 || ss == 0x07) { return FALSE; } /* read block size from end of header? */ if (bs == 6) bs_from_end = 8; else if (bs == 7) bs_from_end = 16; /* read sample rate from end of header? */ if (sr == 0x0C) sr_from_end = 8; else if (sr == 0x0D || sr == 0x0E) sr_from_end = 16; val = data[4]; /* This is slightly faster than a loop */ if (!(val & 0x80)) { val = 0; } else if ((val & 0xc0) && !(val & 0x20)) { val = 1; } else if ((val & 0xe0) && !(val & 0x10)) { val = 2; } else if ((val & 0xf0) && !(val & 0x08)) { val = 3; } else if ((val & 0xf8) && !(val & 0x04)) { val = 4; } else if ((val & 0xfc) && !(val & 0x02)) { val = 5; } else if ((val & 0xfe) && !(val & 0x01)) { val = 6; } else { GST_LOG_OBJECT (flacdec, "failed to read sample/frame"); return FALSE; } val++; headerlen = 4 + val + (bs_from_end / 8) + (sr_from_end / 8); if (gst_flac_calculate_crc8 (data, headerlen) != data[headerlen]) { GST_LOG_OBJECT (flacdec, "invalid checksum"); return FALSE; } if (!last_sample_num) return TRUE; /* FIXME: This is can be 36 bit if variable block size is used, * fortunately not encoder supports this yet and we check for that * above. */ val = (guint32) g_utf8_get_char_validated ((gchar *) data + 4, -1); if (val == (guint32) - 1 || val == (guint32) - 2) { GST_LOG_OBJECT (flacdec, "failed to read sample/frame"); return FALSE; } if (flacdec->min_blocksize == flacdec->max_blocksize) { *last_sample_num = (val + 1) * flacdec->min_blocksize; } else { *last_sample_num = 0; /* FIXME: + length of last block in samples */ } /* FIXME: only valid for fixed block size streams */ GST_DEBUG_OBJECT (flacdec, "frame number: %" G_GINT64_FORMAT, *last_sample_num); if (flacdec->info.rate > 0 && *last_sample_num != 0) { GST_DEBUG_OBJECT (flacdec, "last sample %" G_GINT64_FORMAT " = %" GST_TIME_FORMAT, *last_sample_num, GST_TIME_ARGS (*last_sample_num * GST_SECOND / flacdec->info.rate)); } return TRUE; }
/* FIXME: for our purposes it's probably enough to just check for the sync * marker - we just want to know if it's a header frame or not */ static gboolean gst_flac_dec_scan_got_frame (GstFlacDec * flacdec, const guint8 * data, guint size) { guint headerlen; guint sr_from_end = 0; /* can be 0, 8 or 16 */ guint bs_from_end = 0; /* can be 0, 8 or 16 */ guint32 val = 0; guint8 bs, sr, ca, ss, pb; gboolean vbs; if (size < 10) return FALSE; /* sync */ if (data[0] != 0xFF || (data[1] & 0xFC) != 0xF8) return FALSE; vbs = ! !(data[1] & 1); /* variable blocksize */ bs = (data[2] & 0xF0) >> 4; /* blocksize marker */ sr = (data[2] & 0x0F); /* samplerate marker */ ca = (data[3] & 0xF0) >> 4; /* channel assignment */ ss = (data[3] & 0x0F) >> 1; /* sample size marker */ pb = (data[3] & 0x01); /* padding bit */ GST_LOG_OBJECT (flacdec, "got sync, vbs=%d,bs=%x,sr=%x,ca=%x,ss=%x,pb=%x", vbs, bs, sr, ca, ss, pb); if (bs == 0 || sr == 0x0F || ca >= 0x0B || ss == 0x03 || ss == 0x07) { return FALSE; } /* read block size from end of header? */ if (bs == 6) bs_from_end = 8; else if (bs == 7) bs_from_end = 16; /* read sample rate from end of header? */ if (sr == 0x0C) sr_from_end = 8; else if (sr == 0x0D || sr == 0x0E) sr_from_end = 16; val = data[4]; /* This is slightly faster than a loop */ if (!(val & 0x80)) { val = 0; } else if ((val & 0xc0) && !(val & 0x20)) { val = 1; } else if ((val & 0xe0) && !(val & 0x10)) { val = 2; } else if ((val & 0xf0) && !(val & 0x08)) { val = 3; } else if ((val & 0xf8) && !(val & 0x04)) { val = 4; } else if ((val & 0xfc) && !(val & 0x02)) { val = 5; } else if ((val & 0xfe) && !(val & 0x01)) { val = 6; } else { GST_LOG_OBJECT (flacdec, "failed to read sample/frame"); return FALSE; } val++; headerlen = 4 + val + (bs_from_end / 8) + (sr_from_end / 8); if (gst_flac_calculate_crc8 (data, headerlen) != data[headerlen]) { GST_LOG_OBJECT (flacdec, "invalid checksum"); return FALSE; } return TRUE; }