Skip to content

Instantly share code, notes, and snippets.

@Zinfidel
Last active May 9, 2021 00:15
Show Gist options
  • Save Zinfidel/aa682eb9e19ab22f297ab23146f5018a to your computer and use it in GitHub Desktop.
Save Zinfidel/aa682eb9e19ab22f297ab23146f5018a to your computer and use it in GitHub Desktop.
Opus original sample tag replacer
// See RFC 3533 for ogg header format (https://tools.ietf.org/html/rfc3533#section-6)
// See RFC 7845 for opus header format (https://tools.ietf.org/html/rfc7845#section-5)
#include <stdio.h>
#include <string.h>
#include "osample.h"
static word32 crc_table[256]; // Table of 8-bit remainders for crc
int main(int argc, char* argv[]) {
// Argument parsing
if (argc < 3)
return -1;
const char* filename = argv[1];
int origRate = strtoul(argv[2], NULL, 10);
if (origRate == 0 || origRate == LONG_MIN || origRate == LONG_MAX)
return -1;
FILE* fp;
fopen_s(&fp, filename, "r+b");
if (fp == NULL)
return -1;
// Read ogg header page up to page segment count.
byte headerPage[PAGE_BUFFER_SIZE] = { 0 };
byte* pagePtr = headerPage;
size_t bytesToRead = OGG_PSEGS_OFFSET + 1;
size_t bytesRead = 0;
bytesRead = fread_s(pagePtr, sizeof(headerPage), sizeof(byte), bytesToRead, fp);
pagePtr += bytesRead;
if (bytesRead != bytesToRead)
return -1;
// Read segment lacing values to figure out total page size.
int pageSegments = headerPage[OGG_PSEGS_OFFSET];
size_t headerSize = OGG_STATIC_SIZE + pageSegments;
bytesRead = fread_s(pagePtr, sizeof(headerPage) - bytesRead, sizeof(byte), pageSegments, fp);
if (bytesRead != pageSegments)
return -1;
size_t pageSize = headerSize;
for (int i = 0; i < pageSegments; i++)
pageSize += *pagePtr++;
// Read the rest of the header and page content, and check that we got the Opus page.
bytesToRead = pageSize - headerSize;
if ((sizeof(headerPage) - headerSize) < bytesToRead)
return -1; // Not sure how a header could be this big but it's technically possible.
bytesRead = fread_s(pagePtr, sizeof(headerPage) - headerSize, sizeof(byte), bytesToRead, fp);
if (bytesRead != bytesToRead)
return -1;
char opusMagicString[9] = { 0 };
errno_t err = strncpy_s(opusMagicString, 9, headerPage + headerSize, 8);
if (err != 0 || strcmp(opusMagicString, "OpusHead") != 0)
return -1;
// Set the original frequency, calculate CRC, write out to file.
*((word32*)(headerPage + OGG_CRC_OFFSET)) = 0x00000000;
*((word32*)(pagePtr + OPUS_ORIGSAMP_OFFSET)) = host_to_le_ulong(origRate);
gen_crc_table();
word32 crc = update_crc(0, headerPage, pageSize);
word32 outBuf[2] = { host_to_le_ulong(crc), host_to_le_ulong(origRate) };
fseek(fp, OGG_CRC_OFFSET, SEEK_SET);
fwrite(&outBuf[0], sizeof(word32), 1, fp);
fseek(fp, headerSize + OPUS_ORIGSAMP_OFFSET, SEEK_SET);
fwrite(&outBuf[1], sizeof(word32), 1, fp);
fclose(fp);
return 0;
}
void gen_crc_table(void)
{
register word16 i, j;
register word32 crc_accum;
for (i = 0; i < 256; i++)
{
crc_accum = ((word32)i << 24);
for (j = 0; j < 8; j++)
{
if (crc_accum & 0x80000000L)
crc_accum = (crc_accum << 1) ^ POLYNOMIAL;
else
crc_accum = (crc_accum << 1);
}
crc_table[i] = crc_accum;
}
}
word32 update_crc(word32 crc_accum, byte* data_blk_ptr, word32 data_blk_size)
{
register word32 i, j;
for (j = 0; j < data_blk_size; j++)
{
i = ((int)(crc_accum >> 24) ^ *data_blk_ptr++) & 0xFF;
crc_accum = (crc_accum << 8) ^ crc_table[i];
}
//crc_accum = ~crc_accum;
return crc_accum;
}
#pragma once
#include <Windows.h>
#if REG_DWORD == REG_DWORD_LITTLE_ENDIAN
# define host_to_le_ulong(VAL) VAL
#else
# define host_to_le_ulong(VAL) _byteswap_ulong(VAL)
#endif
#define PAGE_BUFFER_SIZE 2048
#define OGG_STATIC_SIZE 27
#define OGG_CRC_OFFSET 22
#define OGG_PSEGS_OFFSET 26
#define OPUS_ORIGSAMP_OFFSET 12
#define POLYNOMIAL 0x04c11db7L // Standard CRC-32 ppolynomial
typedef unsigned char byte; // Byte is a char
typedef unsigned short int word16; // 16-bit word is a short int
typedef unsigned int word32; // 32-bit word is an int
void gen_crc_table(void);
word32 update_crc(word32 crc_accum, byte* data_blk_ptr, word32 data_blk_size);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment