mirror of
https://github.com/fmang/opustags.git
synced 2024-11-06 05:27:23 +01:00
Renumber the pages past the OpusTags packet
We will soon be able to process OpusTags packets spanning multiple pages, which would offset the page number of all the succeeding pages. This change prepares the process loop for that feature.
This commit is contained in:
parent
bbe03f8030
commit
d88498e4fd
@ -358,6 +358,13 @@ static void process(ot::ogg_reader& reader, ot::ogg_writer* writer, const ot::op
|
||||
{
|
||||
bool focused = false; /*< the stream on which we operate is defined */
|
||||
int focused_serialno; /*< when focused, the serialno of the focused stream */
|
||||
|
||||
/** When the number of pages the OpusTags packet takes differs from the input stream to the
|
||||
* output stream, we need to renumber all the succeeding pages. If the input stream
|
||||
* contains gaps, the offset will naively reproduce the gaps: page numbers 0 (1) 2 4 will
|
||||
* become 0 (1 2) 3 5, where (…) is the OpusTags packet, and not 0 (1 2) 3 4. */
|
||||
int pageno_offset = 0;
|
||||
|
||||
while (reader.next_page()) {
|
||||
auto serialno = ogg_page_serialno(&reader.page);
|
||||
auto pageno = ogg_page_pageno(&reader.page);
|
||||
@ -384,11 +391,13 @@ static void process(ot::ogg_reader& reader, ot::ogg_writer* writer, const ot::op
|
||||
}
|
||||
auto packet = ot::render_tags(tags);
|
||||
writer->write_header_packet(serialno, pageno, packet);
|
||||
pageno_offset = writer->next_page_no - 1 - reader.absolute_page_no;
|
||||
} else {
|
||||
ot::print_comments(tags.comments, stdout, opt.raw);
|
||||
break;
|
||||
}
|
||||
} else if (writer) {
|
||||
ot::renumber_page(reader.page, pageno + pageno_offset);
|
||||
writer->write_page(reader.page);
|
||||
}
|
||||
}
|
||||
|
19
src/ogg.cc
19
src/ogg.cc
@ -86,6 +86,12 @@ void ot::ogg_writer::write_page(const ogg_page& page)
|
||||
{
|
||||
if (page.header_len < 0 || page.body_len < 0)
|
||||
throw status {st::int_overflow, "Overflowing page length"};
|
||||
|
||||
long pageno = ogg_page_pageno(&page);
|
||||
if (pageno != next_page_no)
|
||||
fprintf(stderr, "Output page number mismatch: expected %ld, got %ld.\n", next_page_no, pageno);
|
||||
next_page_no = pageno + 1;
|
||||
|
||||
auto header_len = static_cast<size_t>(page.header_len);
|
||||
auto body_len = static_cast<size_t>(page.body_len);
|
||||
if (fwrite(page.header, 1, header_len, file) < header_len)
|
||||
@ -116,3 +122,16 @@ void ot::ogg_writer::write_header_packet(int serialno, int pageno, ogg_packet& p
|
||||
if (ogg_stream_check(&stream) != 0)
|
||||
throw status {st::libogg_error, "ogg_stream_check failed"};
|
||||
}
|
||||
|
||||
void ot::renumber_page(ogg_page& page, long new_pageno)
|
||||
{
|
||||
// Quick optimization: don’t bother recomputing the CRC if the pageno did not change.
|
||||
long old_pageno = ogg_page_pageno(&page);
|
||||
if (old_pageno == new_pageno)
|
||||
return;
|
||||
|
||||
/** The pageno field is located at bytes 18 to 21 (0-indexed, little-endian). */
|
||||
uint32_t le_pageno = htole32(new_pageno);
|
||||
memcpy(&page.header[18], &le_pageno, 4);
|
||||
ogg_page_checksum_set(&page);
|
||||
}
|
||||
|
14
src/opus.cc
14
src/opus.cc
@ -25,20 +25,6 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
# include <endian.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_ENDIAN_H
|
||||
# include <sys/endian.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define htole32(x) OSSwapHostToLittleInt32(x)
|
||||
#define le32toh(x) OSSwapLittleToHostInt32(x)
|
||||
#endif
|
||||
|
||||
ot::opus_tags ot::parse_tags(const ogg_packet& packet)
|
||||
{
|
||||
if (packet.bytes < 0)
|
||||
|
@ -39,6 +39,20 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
# include <endian.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_ENDIAN_H
|
||||
# include <sys/endian.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define htole32(x) OSSwapHostToLittleInt32(x)
|
||||
#define le32toh(x) OSSwapLittleToHostInt32(x)
|
||||
#endif
|
||||
|
||||
namespace ot {
|
||||
|
||||
/**
|
||||
@ -299,6 +313,11 @@ struct ogg_writer {
|
||||
* Path to the output file.
|
||||
*/
|
||||
std::optional<std::string> path;
|
||||
/**
|
||||
* Custom counter for the sequential page number to be written. It allows us to detect
|
||||
* ogg_page_pageno mismatches and renumber the pages if needed.
|
||||
*/
|
||||
long next_page_no = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -318,6 +337,9 @@ private:
|
||||
std::unique_ptr<unsigned char[]> data;
|
||||
};
|
||||
|
||||
/** Update the Ogg pageno field in the given page. The CRC is recomputed if needed. */
|
||||
void renumber_page(ogg_page& page, long new_pageno);
|
||||
|
||||
/** \} */
|
||||
|
||||
/***********************************************************************************************//**
|
||||
|
19
t/ogg.cc
19
t/ogg.cc
@ -139,12 +139,29 @@ void check_identification()
|
||||
throw failure("was not the beginning of a stream");
|
||||
}
|
||||
|
||||
void check_renumber_page()
|
||||
{
|
||||
ot::file input = fopen("gobble.opus", "r");
|
||||
if (input == nullptr)
|
||||
throw failure("could not open gobble.opus");
|
||||
|
||||
ot::ogg_reader reader(input.get());
|
||||
if (reader.next_page() != true)
|
||||
throw failure("could not read the first page");
|
||||
|
||||
long new_pageno = 1234;
|
||||
ot::renumber_page(reader.page, new_pageno);
|
||||
if (ogg_page_pageno(&reader.page) != new_pageno)
|
||||
throw failure("renumbering failed");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::cout << "1..4\n";
|
||||
std::cout << "1..5\n";
|
||||
run(check_ref_ogg, "check a reference ogg stream");
|
||||
run(check_memory_ogg, "build and check a fresh stream");
|
||||
run(check_bad_stream, "read a non-ogg stream");
|
||||
run(check_identification, "stream identification");
|
||||
run(check_renumber_page, "page renumbering");
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user