[opus] Why does this code not generate a valid opus file?
Timothy B. Terriberry
tterriberry at mozilla.com
Sat Oct 17 15:14:33 PDT 2015
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-skip
This 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 = -1
https://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
More information about the opus
mailing list