Daniel Armyr
2015-Oct-17 20:26 UTC
[opus] Why does this code not generate a valid opus file?
Hi.
I assume that I am deeply stupid and have missed something obvious, but why does
this bare-bones code not generate a valid (If trivial) opus file?
Running opusinfo I ge the following which I interpret this to mean that not even
the first packet gets a pass:
New logical stream (#1, serial: 1f0cce42): type opus
WARNING: Could not decode Opus header packet 0 - invalid Opus stream (1)
WARNING: Could not decode Opus header packet 0 - invalid Opus stream (1)
Opus stream 1:
WARNING: stream 1 is empty
Logical stream 1 ended
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include "ogg/ogg.h"
//Some structs to help build the headers.
struct OggHeader {
unsigned char magicSignature[8];
unsigned char version;
unsigned char channelCount;
unsigned short preSkip;
unsigned int sampleRate;
unsigned short outputGain;
unsigned char mappingFamily;
};
struct OggCommentHeader {
unsigned char magicSignature[8];
unsigned int vendorStringLength; //Must be set to 0
//In-between here we would place out vendor string, if we had one.
unsigned int userCommentListLength; //Must be set to 0
//And after here we would place our comments, if we had any.
};
int main(){
ogg_stream_state os;
ogg_page og;
FILE* fout = fopen("/tmp/trivial.opus", "wb");
if ( fout == 0 ) {
printf( "Error opening output file.\n" );
return -1;
}
//**************
//Initialize the stream
srand(0);
ogg_stream_init(&os,rand());
//**************
//Create the header
//*****************
struct OggHeader headerContent = {
{'O', 'p', 'u', 's', 'H',
'e', 'a', 'd'},
1, //Version
2, //Channels
0, //pre-skip
44100, //Original samplerate
0, //output gain
0}; //Mapping family
ogg_packet header;
header.packet = (unsigned char*)&headerContent;
header.bytes = sizeof(struct OggHeader);
header.b_o_s = 1; //Header must set beginning_of_stream
header.e_o_s = 0;
header.granulepos = -1; //This packet does not contain audio data, so
granule-position = -1
header.packetno = 0;
ogg_stream_packetin(&os,&header);
//**************
//Create the comments header
struct OggCommentHeader commentHeaderContent = {
{'O', 'p', 'u', 's', 'T',
'a', 'g', 's'},
0, //We do not support a vandor string in this implementation.
0 //We do not support any user comments in this implementation.
};
ogg_packet header_comm;
header_comm.packet = (unsigned char*)&commentHeaderContent;
header_comm.bytes = sizeof(struct OggCommentHeader);
header_comm.b_o_s = 0;
header_comm.e_o_s = 1; //We are ending the stream as there will be no data.
header_comm.granulepos = -1; //This packet does not contain audio data, so
granule-position = -1
header_comm.packetno = 1; //Second packet.
ogg_stream_packetin(&os,&header_comm);
//***************
//Write everything out.
while(1){
int result=ogg_stream_flush(&os,&og);
if(result==0)break;
fwrite(og.header,1,og.header_len,fout);
fwrite(og.body,1,og.body_len,fout);
}
//And clean up.
ogg_stream_clear(&os);
fclose(fout);
printf("Done.\n");
return 0;
}
//Sincerely
Daniel Armyr
Beginner opus user
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
http://lists.xiph.org/pipermail/opus/attachments/20151017/a0c223b1/attachment-0001.htm
Timothy B. Terriberry
2015-Oct-17 22:14 UTC
[opus] Why does this code not generate a valid opus file?
Comments inline. Daniel Armyr <daniel at armyr.se> wrote:> Hi. > I assume that I am deeply stupid and have missed something obvious, > but why does this bare-bones code not generate a valid (If trivial) > opus file? > > Running opusinfo I ge the following which I interpret this to mean > that not even the first packet gets a pass: > New logical stream (#1, serial: 1f0cce42): type opus > WARNING: Could not decode Opus header packet 0 - invalid Opus stream (1) > WARNING: Could not decode Opus header packet 0 - invalid Opus stream (1) > Opus stream 1: > WARNING: stream 1 is empty > Logical stream 1 ended > > Here is my code: > > #include <stdio.h> > #include <stdlib.h> > #include "ogg/ogg.h" > > //Some structs to help build the headers. > struct OggHeader { > unsigned char magicSignature[8]; > unsigned char version; > unsigned char channelCount; > unsigned short preSkip; > unsigned int sampleRate; > unsigned short outputGain; > unsigned char mappingFamily; > }; > > struct OggCommentHeader { > unsigned char magicSignature[8]; > unsigned int vendorStringLength; //Must be set to 0 > //In-between here we would place out vendor string, if we had one. > unsigned int userCommentListLength; //Must be set to 0 > //And after here we would place our comments, if we had any. > }; > > int main(){ > ogg_stream_state os; > ogg_page og; > > FILE* fout = fopen("/tmp/trivial.opus", "wb"); > if ( fout == 0 ) { > printf( "Error opening output file.\n" ); > return -1; > } > > //************** > //Initialize the stream > srand(0); > ogg_stream_init(&os,rand()); > > //************** > //Create the header > //***************** > struct OggHeader headerContent = { > {'O', 'p', 'u', 's', 'H', 'e', 'a', 'd'}, > 1, //Version > 2, //Channels > 0, //pre-skipThis will generate warnings, as no reasonable Opus encoder would set this smaller than 120 (and then only if it were a CELT-only stream).> 44100, //Original samplerate > 0, //output gain > 0}; //Mapping family > > ogg_packet header; > header.packet = (unsigned char*)&headerContent; > header.bytes = sizeof(struct OggHeader);Are you sure this is returning the correct number, and not adding padding for alignment purposes? opusinfo will reject headers with more than 19 bytes for channel mapping family 0 and minor versions 0 or 1. Then, because it failed to parse the initial header, it will attempt to parse the comment header as if it were the initial header, and that will fail again.> header.b_o_s = 1; //Header must set beginning_of_stream > header.e_o_s = 0; > header.granulepos = -1; //This packet does not contain audio > data, so granule-position = -1https://tools.ietf.org/html/draft-ietf-codec-oggopus-08#section-3 "There are two mandatory header packets. The granule position of the pages on which these packets complete MUST be zero."> header.packetno = 0; > > ogg_stream_packetin(&os,&header); > > //************** > //Create the comments header > struct OggCommentHeader commentHeaderContent = { > {'O', 'p', 'u', 's', 'T', 'a', 'g', 's'}, > 0, //We do not support a vandor string in this implementation. > 0 //We do not support any user comments in this implementation. > }; > > ogg_packet header_comm; > header_comm.packet = (unsigned char*)&commentHeaderContent; > header_comm.bytes = sizeof(struct OggCommentHeader); > header_comm.b_o_s = 0; > header_comm.e_o_s = 1; //We are ending the stream as there will > be no data. > header_comm.granulepos = -1; //This packet does not contain > audio data, so granule-position = -1 > header_comm.packetno = 1; //Second packet. > > ogg_stream_packetin(&os,&header_comm); > > //*************** > //Write everything out. > while(1){ > int result=ogg_stream_flush(&os,&og); > if(result==0)break; > fwrite(og.header,1,og.header_len,fout); > fwrite(og.body,1,og.body_len,fout); > } > > //And clean up. > ogg_stream_clear(&os); > > fclose(fout); > > printf("Done.\n"); > return 0; > } > > //Sincerely > Daniel Armyr > Beginner opus user