Bool gf_eac3_parser_bs(GF_BitStream *bs, GF_AC3Header *hdr, Bool full_parse)
{
	u32 fscod, bsid, ac3_mod, freq, framesize, syncword, substreamid, lfon, channels, numblkscod;
	u64 pos;

restart:
	if (!hdr || (gf_bs_available(bs) < 6))
		return GF_FALSE;
	if (!AC3_FindSyncCodeBS(bs))
		return GF_FALSE;

	pos = gf_bs_get_position(bs);
	framesize = 0;
	numblkscod = 0;

block:
	syncword = gf_bs_read_u16(bs);
	if (syncword != 0x0B77) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[E-AC3] Wrong sync word detected (0x%X - expecting 0x0B77).\n", syncword));
		return GF_FALSE;
	}

	gf_bs_read_int(bs, 2); //strmtyp
	substreamid = gf_bs_read_int(bs, 3);
	framesize += gf_bs_read_int(bs, 11);
	fscod = gf_bs_read_int(bs, 2);
	if (fscod == 0x3) {
		fscod = gf_bs_read_int(bs, 2);
		numblkscod += 6;
	} else {
		numblkscod += gf_bs_read_int(bs, 2);
	}
	assert(numblkscod <= 9);

	if ((hdr->substreams >> substreamid) & 0x1) {
		if (!substreamid) {
			hdr->framesize = framesize;

			if (numblkscod < 6) { //we need 6 blocks to make a sample
				gf_bs_seek(bs, pos+2*framesize);
				if ((gf_bs_available(bs) < 6) || !AC3_FindSyncCodeBS(bs))
					return GF_FALSE;
				goto block;
			}

			gf_bs_seek(bs, pos);
			return GF_TRUE;
		} else {
			GF_LOG(GF_LOG_INFO, GF_LOG_CODING, ("[E-AC3] Detected sample in substream id=%u. Skipping.\n", substreamid));
			gf_bs_seek(bs, pos+framesize);
			goto restart;
		}
	}
	hdr->substreams |= (1 << substreamid);

	switch (fscod) {
	case 0:
		freq = 48000;
		break;
	case 1:
		freq = 44100;
		break;
	case 2:
		freq = 32000;
		break;
	default:
		return GF_FALSE;
	}

	ac3_mod = gf_bs_read_int(bs, 3);
	lfon = gf_bs_read_int(bs, 1);
	bsid = gf_bs_read_int(bs, 5);
	if (!substreamid && (bsid!=16/*E-AC3*/))
		return GF_FALSE;

	channels = ac3_mod_to_chans[ac3_mod];
	if (lfon)
		channels += 1;

	if (substreamid) {
		GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[E-AC3] Detected additional %u channels in substream id=%u - may not be handled correctly. Skipping.\n", channels, substreamid));
		gf_bs_seek(bs, pos+framesize);
		goto restart;
	} else {
		hdr->bitrate = 0;
		hdr->sample_rate = freq;
		hdr->framesize = framesize;
		hdr->lfon = lfon;
		hdr->channels = channels;
		if (full_parse) {
			hdr->bsid = bsid;
			hdr->bsmod = 0;
			hdr->acmod = ac3_mod;
			hdr->fscod = fscod;
			hdr->brcode = 0;
		}
	}

	if (numblkscod < 6) { //we need 6 blocks to make a sample
		gf_bs_seek(bs, pos+2*framesize);
		if ((gf_bs_available(bs) < 6) || !AC3_FindSyncCodeBS(bs))
			return GF_FALSE;
		goto block;
	}

	gf_bs_seek(bs, pos);

	return GF_TRUE;
}
Bool gf_eac3_parser_bs(GF_BitStream *bs, GF_AC3Header *hdr, Bool full_parse)
{
	u32 fscod, bsid, ac3_mod, freq, framesize, syncword, substreamid, lfon, channels, numblkscod;
	u64 pos;

restart:
	if (!hdr || (gf_bs_available(bs) < 6))
		return GF_FALSE;
	if (!AC3_FindSyncCodeBS(bs))
		return GF_FALSE;

	pos = gf_bs_get_position(bs);
	framesize = 0;
	numblkscod = 0;

block:
	syncword = gf_bs_read_u16(bs);
	if (syncword != 0x0B77) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[E-AC3] Wrong sync word detected (0x%X - expecting 0x0B77).\n", syncword));
		return GF_FALSE;
	}

	gf_bs_read_int(bs, 2);  
	substreamid = gf_bs_read_int(bs, 3);
	framesize += gf_bs_read_int(bs, 11);
	fscod = gf_bs_read_int(bs, 2);
	if (fscod == 0x3) {
		fscod = gf_bs_read_int(bs, 2);
		numblkscod += 6;
	} else {
		numblkscod += gf_bs_read_int(bs, 2);
	}
	assert(numblkscod <= 9);

	if ((hdr->substreams >> substreamid) & 0x1) {
		if (!substreamid) {
			hdr->framesize = framesize;

			if (numblkscod < 6) {  
				gf_bs_seek(bs, pos+2*framesize);
				if ((gf_bs_available(bs) < 6) || !AC3_FindSyncCodeBS(bs))
					return GF_FALSE;
				goto block;
			}

			gf_bs_seek(bs, pos);
			return GF_TRUE;
		} else {
			GF_LOG(GF_LOG_INFO, GF_LOG_CODING, ("[E-AC3] Detected sample in substream id=%u. Skipping.\n", substreamid));
			gf_bs_seek(bs, pos+framesize);
			goto restart;
		}
	}
	hdr->substreams |= (1 << substreamid);

	switch (fscod) {
	case 0:
		freq = 48000;
		break;
	case 1:
		freq = 44100;
		break;
	case 2:
		freq = 32000;
		break;
	default:
		return GF_FALSE;
	}

	ac3_mod = gf_bs_read_int(bs, 3);
	lfon = gf_bs_read_int(bs, 1);
	bsid = gf_bs_read_int(bs, 5);
	if (!substreamid && (bsid!=16 ))
		return GF_FALSE;

	channels = ac3_mod_to_chans[ac3_mod];
	if (lfon)
		channels += 1;

	if (substreamid) {
		GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[E-AC3] Detected additional %u channels in substream id=%u - may not be handled correctly. Skipping.\n", channels, substreamid));
		gf_bs_seek(bs, pos+framesize);
		goto restart;
	} else {
		hdr->bitrate = 0;
		hdr->sample_rate = freq;
		hdr->framesize = framesize;
		hdr->lfon = lfon;
		hdr->channels = channels;
		if (full_parse) {
			hdr->bsid = bsid;
			hdr->bsmod = 0;
			hdr->acmod = ac3_mod;
			hdr->fscod = fscod;
			hdr->brcode = 0;
		}
	}

	if (numblkscod < 6) {  
		gf_bs_seek(bs, pos+2*framesize);
		if ((gf_bs_available(bs) < 6) || !AC3_FindSyncCodeBS(bs))
			return GF_FALSE;
		goto block;
	}

	gf_bs_seek(bs, pos);

	return GF_TRUE;
}