introduce ot::is_opus_stream

This commit is contained in:
Frédéric Mangano-Tarumi 2018-12-08 11:24:17 -05:00
parent f080f9da70
commit 23049a7ff6
3 changed files with 53 additions and 1 deletions

View File

@ -14,6 +14,15 @@
using namespace std::literals::string_literals;
bool ot::is_opus_stream(const ogg_page& identification_header)
{
if (ogg_page_bos(&identification_header) == 0)
return false;
if (identification_header.body_len < 8)
return false;
return (memcmp(identification_header.body, "OpusHead", 8) == 0);
}
ot::status ot::ogg_reader::read_page()
{
while (ogg_sync_pageout(&sync, &page) != 1) {

View File

@ -146,6 +146,13 @@ struct ogg_logical_stream : ogg_stream_state {
}
};
/**
* Identify the codec of a logical stream based on the first bytes of the first packet of the first
* page. For Opus, the first 8 bytes must be OpusHead. Any other signature is assumed to be another
* codec.
*/
bool is_opus_stream(const ogg_page& identification_header);
/**
* Ogg reader, combining a FILE input, an ogg_sync_state reading the pages.
*

View File

@ -14,6 +14,8 @@ static void check_ref_ogg()
ot::status rc = reader.read_page();
if (rc != ot::st::ok)
throw failure("could not read the first page");
if (!ot::is_opus_stream(reader.page))
throw failure("failed to identify the stream as opus");
rc = reader.read_header_packet([](ogg_packet& p) {
if (p.bytes != 19)
throw failure("unexpected length for the first packet");
@ -114,10 +116,44 @@ static void check_memory_ogg()
}
}
void check_identification()
{
auto good_header = (unsigned char*)
"\x4f\x67\x67\x53\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x42\xf2"
"\xe6\xc7\x00\x00\x00\x00\x7e\xc3\x57\x2b\x01\x13";
auto good_body = (unsigned char*) "OpusHeadABCD";
ogg_page id;
id.header = good_header;
id.header_len = 28;
id.body = good_body;
id.body_len = 12;
if (!ot::is_opus_stream(id))
throw failure("could not identify opus header");
// Bad body
id.body_len = 7;
if (ot::is_opus_stream(id))
throw failure("opus header was too short to be valid");
id.body_len = 12;
id.body = (unsigned char*) "Not_OpusHead";
if (ot::is_opus_stream(id))
throw failure("was not an opus header");
id.body = good_body;
// Remove the BoS bit from the header.
id.header = (unsigned char*)
"\x4f\x67\x67\x53\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x42\xf2"
"\xe6\xc7\x00\x00\x00\x00\x7e\xc3\x57\x2b\x01\x13";
if (ot::is_opus_stream(id))
throw failure("was not the beginning of a stream");
}
int main(int argc, char **argv)
{
std::cout << "1..2\n";
std::cout << "1..3\n";
run(check_ref_ogg, "check a reference ogg stream");
run(check_memory_ogg, "build and check a fresh stream");
run(check_identification, "stream identification");
return 0;
}