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