/*! * \brief Create a new OGG/Speex filestream and set it up for reading. * \param fs File that points to on disk storage of the OGG/Speex data. * \return The new filestream. */ static int ogg_speex_open(struct ast_filestream *fs) { char *buffer; size_t bytes; struct speex_desc *s = (struct speex_desc *)fs->_private; SpeexHeader *hdr = NULL; int i, result, expected_rate; expected_rate = ast_format_get_sample_rate(fs->fmt->format); s->serialno = -1; ogg_sync_init(&s->oy); buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, fs->f); ogg_sync_wrote(&s->oy, bytes); result = ogg_sync_pageout(&s->oy, &s->og); if (result != 1) { if(bytes < BLOCK_SIZE) { ast_log(LOG_ERROR, "Run out of data...\n"); } else { ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n"); } ogg_sync_clear(&s->oy); return -1; } ogg_stream_init(&s->os, ogg_page_serialno(&s->og)); if (ogg_stream_pagein(&s->os, &s->og) < 0) { ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n"); goto error; } if (read_packet(fs) < 0) { ast_log(LOG_ERROR, "Error reading initial header packet.\n"); goto error; } hdr = speex_packet_to_header((char*)s->op.packet, s->op.bytes); if (memcmp(hdr->speex_string, "Speex ", 8)) { ast_log(LOG_ERROR, "OGG container does not contain Speex audio!\n"); goto error; } if (hdr->frames_per_packet != 1) { ast_log(LOG_ERROR, "Only one frame-per-packet OGG/Speex files are currently supported!\n"); goto error; } if (hdr->nb_channels != 1) { ast_log(LOG_ERROR, "Only monophonic OGG/Speex files are currently supported!\n"); goto error; } if (hdr->rate != expected_rate) { ast_log(LOG_ERROR, "Unexpected sampling rate (%d != %d)!\n", hdr->rate, expected_rate); goto error; } /* this packet is the comment */ if (read_packet(fs) < 0) { ast_log(LOG_ERROR, "Error reading comment packet.\n"); goto error; } for (i = 0; i < hdr->extra_headers; i++) { if (read_packet(fs) < 0) { ast_log(LOG_ERROR, "Error reading extra header packet %d.\n", i+1); goto error; } } speex_header_free(hdr); return 0; error: if (hdr) { speex_header_free(hdr); } ogg_stream_clear(&s->os); ogg_sync_clear(&s->oy); return -1; }
/* Opens the Ogg stream, searching for and initializing Theora and Vorbis media */ int alogg_open(APEG_LAYER *layer) { ALOGG_INFO *info; int vok = 0, aok = 0; int flag, cs, size; info = calloc(1, sizeof(ALOGG_INFO)); if(!info) return APEG_ERROR; LOCK_DATA(info, sizeof(ALOGG_INFO)); ogg_sync_init(&info->osync); theora_comment_init(&info->tcomment); theora_info_init(&info->tinfo); vorbis_info_init(&info->vinfo); vorbis_comment_init(&info->vcomment); flag = FALSE; while(!flag) { int ret = buffer_data(layer, info); if(ret == 0) break; while(ogg_sync_pageout(&info->osync, &info->opage) > 0) { ogg_stream_state test; /* is this a mandated initial header? If not, stop parsing */ if(!ogg_page_bos(&info->opage)) { if(vok > 0) ogg_stream_pagein(&info->ostream[0], &info->opage); if(aok > 0) ogg_stream_pagein(&info->ostream[1], &info->opage); flag = TRUE; break; } ogg_stream_init(&test, ogg_page_serialno(&info->opage)); ogg_stream_pagein(&test, &info->opage); ogg_stream_packetout(&test, &info->opkt); /* identify the codec: try theora */ if(!vok && theora_decode_header(&info->tinfo, &info->tcomment, &info->opkt) >= 0) { /* it is theora */ if(!_apeg_ignore_video) { memcpy(&info->ostream[0], &test, sizeof(test)); vok = 1; } else ogg_stream_clear(&test); } else if(!aok && vorbis_synthesis_headerin(&info->vinfo, &info->vcomment, &info->opkt) >= 0) { /* it is vorbis */ if(!_apeg_ignore_audio) { memcpy(&info->ostream[1], &test, sizeof(test)); aok = 1; } else ogg_stream_clear(&test); } /* whatever it is, we don't care about it */ else ogg_stream_clear(&test); } /* fall through to non-bos page parsing */ } /* look for further theora headers */ while((vok > 0 && vok < 3) || (aok > 0 && aok < 3)) { int ret; // Get the last two of three Theora headers while(vok > 0 && vok < 3 && (ret = ogg_stream_packetout(&info->ostream[0], &info->opkt))) { if(ret < 0) goto error; if(theora_decode_header(&info->tinfo, &info->tcomment, &info->opkt)) goto error; ++vok; } // Get the last two of three Vorbis headers while(aok > 0 && aok < 3 && (ret = ogg_stream_packetout(&info->ostream[1], &info->opkt))) { if(ret < 0) goto error; if(vorbis_synthesis_headerin(&info->vinfo, &info->vcomment, &info->opkt)) goto error; ++aok; } if(ogg_sync_pageout(&info->osync, &info->opage) <= 0) { /* need more data */ if(buffer_data(layer, info) == 0) break; } else { if(vok > 0) ogg_stream_pagein(&info->ostream[0], &info->opage); if(aok > 0) ogg_stream_pagein(&info->ostream[1], &info->opage); } } // Neither Vorbis or Theora fully initialized. Error. if(vok != 3 && aok != 3) goto error; layer->ogg_info = info; if(aok == 3) { vorbis_synthesis_init(&info->vdsp, &info->vinfo); vorbis_block_init(&info->vdsp, &info->vblock); if(info->vinfo.channels == 1) layer->stream.audio.down_channel = FALSE; layer->stream.audio.channels = info->vinfo.channels; layer->stream.audio.freq = info->vinfo.rate >> layer->stream.audio.down_sample; if(_apeg_audio_reset_parameters(layer) != APEG_OK) { vorbis_block_clear(&info->vblock); vorbis_dsp_clear(&info->vdsp); goto error; } // layer->audio.inited = TRUE; layer->stream.flags |= APEG_VORBIS_AUDIO; }
int main(void){ ogg_stream_init(&os_en,0x04030201); ogg_stream_init(&os_de,0x04030201); ogg_sync_init(&oy); /* Exercise each code path in the framing code. Also verify that the checksums are working. */ { /* 17 only */ const int packets[]={17, -1}; const int *headret[]={head1_0,NULL}; fprintf(stderr,"testing single page encoding... "); test_pack(packets,headret,0,0,0); } { /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; const int *headret[]={head1_1,head2_1,NULL}; fprintf(stderr,"testing basic page encoding... "); test_pack(packets,headret,0,0,0); } { /* nil packets; beginning,middle,end */ const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; const int *headret[]={head1_2,head2_2,NULL}; fprintf(stderr,"testing basic nil packets... "); test_pack(packets,headret,0,0,0); } { /* large initial packet */ const int packets[]={4345,259,255,-1}; const int *headret[]={head1_3,head2_3,NULL}; fprintf(stderr,"testing initial-packet lacing > 4k... "); test_pack(packets,headret,0,0,0); } { /* continuing packet test */ const int packets[]={0,4345,259,255,-1}; const int *headret[]={head1_4,head2_4,head3_4,NULL}; fprintf(stderr,"testing single packet page span... "); test_pack(packets,headret,0,0,0); } /* page with the 255 segment limit */ { const int packets[]={0,10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,50,-1}; const int *headret[]={head1_5,head2_5,head3_5,NULL}; fprintf(stderr,"testing max packet segments... "); test_pack(packets,headret,0,0,0); } { /* packet that overspans over an entire page */ const int packets[]={0,100,9000,259,255,-1}; const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; fprintf(stderr,"testing very large packets... "); test_pack(packets,headret,0,0,0); } { /* test for the libogg 1.1.1 resync in large continuation bug found by Josh Coalson) */ const int packets[]={0,100,9000,259,255,-1}; const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; fprintf(stderr,"testing continuation resync in very large packets... "); test_pack(packets,headret,100,2,3); } { /* term only page. why not? */ const int packets[]={0,100,4080,-1}; const int *headret[]={head1_7,head2_7,head3_7,NULL}; fprintf(stderr,"testing zero data page (1 nil packet)... "); test_pack(packets,headret,0,0,0); } { /* build a bunch of pages for testing */ unsigned char *data=_ogg_malloc(1024*1024); int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1}; int inptr=0,i,j; ogg_page og[5]; ogg_stream_reset(&os_en); for(i=0;pl[i]!=-1;i++){ ogg_packet op; int len=pl[i]; op.packet=data+inptr; op.bytes=len; op.e_o_s=(pl[i+1]<0?1:0); op.granulepos=(i+1)*1000; for(j=0;j<len;j++)data[inptr++]=i+j; ogg_stream_packetin(&os_en,&op); } _ogg_free(data); /* retrieve finished pages */ for(i=0;i<5;i++){ if(ogg_stream_pageout(&os_en,&og[i])==0){ fprintf(stderr,"Too few pages output building sync tests!\n"); exit(1); } copy_page(&og[i]); } /* Test lost pages on pagein/packetout: no rollback */ { ogg_page temp; ogg_packet test; fprintf(stderr,"Testing loss of pages... "); ogg_sync_reset(&oy); ogg_stream_reset(&os_de); for(i=0;i<5;i++){ memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, og[i].header_len); ogg_sync_wrote(&oy,og[i].header_len); memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); ogg_sync_wrote(&oy,og[i].body_len); } ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); /* skip */ ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); /* do we get the expected results/packets? */ if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,0,0,0); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,100,1,-1); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,4079,2,3000); if(ogg_stream_packetout(&os_de,&test)!=-1){ fprintf(stderr,"Error: loss of page did not return error\n"); exit(1); } if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,76,5,-1); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,34,6,-1); fprintf(stderr,"ok.\n"); } /* Test lost pages on pagein/packetout: rollback with continuation */ { ogg_page temp; ogg_packet test; fprintf(stderr,"Testing loss of pages (rollback required)... "); ogg_sync_reset(&oy); ogg_stream_reset(&os_de); for(i=0;i<5;i++){ memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, og[i].header_len); ogg_sync_wrote(&oy,og[i].header_len); memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); ogg_sync_wrote(&oy,og[i].body_len); } ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); /* skip */ ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); /* do we get the expected results/packets? */ if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,0,0,0); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,100,1,-1); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,4079,2,3000); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,2956,3,4000); if(ogg_stream_packetout(&os_de,&test)!=-1){ fprintf(stderr,"Error: loss of page did not return error\n"); exit(1); } if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,300,13,14000); fprintf(stderr,"ok.\n"); } /* the rest only test sync */ { ogg_page og_de; /* Test fractional page inputs: incomplete capture */ fprintf(stderr,"Testing sync on partial inputs... "); ogg_sync_reset(&oy); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 3); ogg_sync_wrote(&oy,3); if(ogg_sync_pageout(&oy,&og_de)>0)error(); /* Test fractional page inputs: incomplete fixed header */ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, 20); ogg_sync_wrote(&oy,20); if(ogg_sync_pageout(&oy,&og_de)>0)error(); /* Test fractional page inputs: incomplete header */ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, 5); ogg_sync_wrote(&oy,5); if(ogg_sync_pageout(&oy,&og_de)>0)error(); /* Test fractional page inputs: incomplete body */ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, og[1].header_len-28); ogg_sync_wrote(&oy,og[1].header_len-28); if(ogg_sync_pageout(&oy,&og_de)>0)error(); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); ogg_sync_wrote(&oy,1000); if(ogg_sync_pageout(&oy,&og_de)>0)error(); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, og[1].body_len-1000); ogg_sync_wrote(&oy,og[1].body_len-1000); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); fprintf(stderr,"ok.\n"); } /* Test fractional page inputs: page + incomplete capture */ { ogg_page og_de; fprintf(stderr,"Testing sync on 1+partial inputs... "); ogg_sync_reset(&oy); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, og[1].header_len); ogg_sync_wrote(&oy,og[1].header_len); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 20); ogg_sync_wrote(&oy,20); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); if(ogg_sync_pageout(&oy,&og_de)>0)error(); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, og[1].header_len-20); ogg_sync_wrote(&oy,og[1].header_len-20); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); fprintf(stderr,"ok.\n"); } /* Test recapture: garbage + page */ { ogg_page og_de; fprintf(stderr,"Testing search for capture... "); ogg_sync_reset(&oy); /* 'garbage' */ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, og[1].header_len); ogg_sync_wrote(&oy,og[1].header_len); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, 20); ogg_sync_wrote(&oy,20); if(ogg_sync_pageout(&oy,&og_de)>0)error(); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); if(ogg_sync_pageout(&oy,&og_de)>0)error(); memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, og[2].header_len-20); ogg_sync_wrote(&oy,og[2].header_len-20); memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, og[2].body_len); ogg_sync_wrote(&oy,og[2].body_len); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); fprintf(stderr,"ok.\n"); } /* Test recapture: page + garbage + page */ { ogg_page og_de; fprintf(stderr,"Testing recapture... "); ogg_sync_reset(&oy); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, og[1].header_len); ogg_sync_wrote(&oy,og[1].header_len); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, og[2].header_len); ogg_sync_wrote(&oy,og[2].header_len); memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, og[2].header_len); ogg_sync_wrote(&oy,og[2].header_len); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, og[2].body_len-5); ogg_sync_wrote(&oy,og[2].body_len-5); memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, og[3].header_len); ogg_sync_wrote(&oy,og[3].header_len); memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, og[3].body_len); ogg_sync_wrote(&oy,og[3].body_len); if(ogg_sync_pageout(&oy,&og_de)>0)error(); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); fprintf(stderr,"ok.\n"); } /* Free page data that was previously copied */ { for(i=0;i<5;i++){ free_page(&og[i]); } } } return(0); }
int ExportOGG::Export(AudacityProject *project, int numChannels, wxString fName, bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec, Tags *metadata, int WXUNUSED(subformat)) { double rate = project->GetRate(); TrackList *tracks = project->GetTracks(); double quality = (gPrefs->Read(wxT("/FileFormats/OggExportQuality"), 50)/(float)100.0); wxLogNull logNo; // temporarily disable wxWidgets error messages int updateResult = eProgressSuccess; int eos = 0; FileIO outFile(fName, FileIO::Output); if (!outFile.IsOpened()) { wxMessageBox(_("Unable to open target file for writing")); return false; } // All the Ogg and Vorbis encoding data ogg_stream_state stream; ogg_page page; ogg_packet packet; vorbis_info info; vorbis_comment comment; vorbis_dsp_state dsp; vorbis_block block; // Encoding setup vorbis_info_init(&info); vorbis_encode_init_vbr(&info, numChannels, int(rate + 0.5), quality); // Retrieve tags if (!FillComment(project, &comment, metadata)) { return false; } // Set up analysis state and auxiliary encoding storage vorbis_analysis_init(&dsp, &info); vorbis_block_init(&dsp, &block); // Set up packet->stream encoder. According to encoder example, // a random serial number makes it more likely that you can make // chained streams with concatenation. srand(time(NULL)); ogg_stream_init(&stream, rand()); // First we need to write the required headers: // 1. The Ogg bitstream header, which contains codec setup params // 2. The Vorbis comment header // 3. The bitstream codebook. // // After we create those our responsibility is complete, libvorbis will // take care of any other ogg bistream constraints (again, according // to the example encoder source) ogg_packet bitstream_header; ogg_packet comment_header; ogg_packet codebook_header; vorbis_analysis_headerout(&dsp, &comment, &bitstream_header, &comment_header, &codebook_header); // Place these headers into the stream ogg_stream_packetin(&stream, &bitstream_header); ogg_stream_packetin(&stream, &comment_header); ogg_stream_packetin(&stream, &codebook_header); // Flushing these headers now guarentees that audio data will // start on a new page, which apparently makes streaming easier while (ogg_stream_flush(&stream, &page)) { outFile.Write(page.header, page.header_len); outFile.Write(page.body, page.body_len); } int numWaveTracks; WaveTrack **waveTracks; tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks); Mixer *mixer = CreateMixer(numWaveTracks, waveTracks, tracks->GetTimeTrack(), t0, t1, numChannels, SAMPLES_PER_RUN, false, rate, floatSample, true, mixerSpec); delete [] waveTracks; ProgressDialog *progress = new ProgressDialog(wxFileName(fName).GetName(), selectionOnly ? _("Exporting the selected audio as Ogg Vorbis") : _("Exporting the entire project as Ogg Vorbis")); while (updateResult == eProgressSuccess && !eos) { float **vorbis_buffer = vorbis_analysis_buffer(&dsp, SAMPLES_PER_RUN); sampleCount samplesThisRun = mixer->Process(SAMPLES_PER_RUN); if (samplesThisRun == 0) { // Tell the library that we wrote 0 bytes - signalling the end. vorbis_analysis_wrote(&dsp, 0); } else { for (int i = 0; i < numChannels; i++) { float *temp = (float *)mixer->GetBuffer(i); memcpy(vorbis_buffer[i], temp, sizeof(float)*SAMPLES_PER_RUN); } // tell the encoder how many samples we have vorbis_analysis_wrote(&dsp, samplesThisRun); } // I don't understand what this call does, so here is the comment // from the example, verbatim: // // vorbis does some data preanalysis, then divvies up blocks // for more involved (potentially parallel) processing. Get // a single block for encoding now while (vorbis_analysis_blockout(&dsp, &block) == 1) { // analysis, assume we want to use bitrate management vorbis_analysis(&block, NULL); vorbis_bitrate_addblock(&block); while (vorbis_bitrate_flushpacket(&dsp, &packet)) { // add the packet to the bitstream ogg_stream_packetin(&stream, &packet); // From vorbis-tools-1.0/oggenc/encode.c: // If we've gone over a page boundary, we can do actual output, // so do so (for however many pages are available). while (!eos) { int result = ogg_stream_pageout(&stream, &page); if (!result) { break; } outFile.Write(page.header, page.header_len); outFile.Write(page.body, page.body_len); if (ogg_page_eos(&page)) { eos = 1; } } } } updateResult = progress->Update(mixer->MixGetCurrentTime()-t0, t1-t0); } delete progress;; delete mixer; ogg_stream_clear(&stream); vorbis_block_clear(&block); vorbis_dsp_clear(&dsp); vorbis_info_clear(&info); vorbis_comment_clear(&comment); outFile.Close(); return updateResult; }
/* Read the speex header. Return 0 on error. */ static int read_speex_header (struct spx_data *data) { int packet_count = 0; int stream_init = 0; char *buf; ssize_t nb_read; int header_packets = 2; while (packet_count < header_packets) { /* Get the ogg buffer for writing */ buf = ogg_sync_buffer (&data->oy, 200); /* Read bitstream from input file */ nb_read = io_read (data->stream, buf, 200); if (nb_read < 0) { decoder_error (&data->error, ERROR_FATAL, 0, "Can't open speex file: IO error: %s", io_strerror(data->stream)); return 0; } if (nb_read == 0) { decoder_error (&data->error, ERROR_FATAL, 0, "Can't open speex header"); return 0; } ogg_sync_wrote (&data->oy, nb_read); /* Loop for all complete pages we got (most likely only one) */ while (ogg_sync_pageout(&data->oy, &data->og) == 1) { if (stream_init == 0) { ogg_stream_init(&data->os, ogg_page_serialno(&data->og)); stream_init = 1; } /* Add page to the bitstream */ ogg_stream_pagein (&data->os, &data->og); /* Extract all available packets FIXME: EOS! */ while (ogg_stream_packetout(&data->os, &data->op) == 1) { /* If first packet, process as Speex header */ if (packet_count == 0) { data->st = process_header (data); if (!data->st) { ogg_stream_clear (&data->os); return 0; } data->rate = data->header->rate; data->nchannels = data->header->nb_channels; data->frames_per_packet = data->header->frames_per_packet; /*data->vbr = data->header->vbr; */ if (!data->frames_per_packet) data->frames_per_packet=1; data->output = xmalloc (data->frame_size * data->nchannels * data->frames_per_packet * sizeof(int16_t)); data->output_start = 0; data->output_left = 0; header_packets += data->header->extra_headers; } else if (packet_count == 1) { data->comment_packet_len = data->op.bytes; data->comment_packet = xmalloc ( sizeof(char) * data->comment_packet_len); memcpy (data->comment_packet, data->op.packet, data->comment_packet_len); } packet_count++; } } } return 1; }
int main(int argc, char **argv) { int nb_samples, total_samples=0, nb_encoded; int c; int option_index = 0; char *inFile, *outFile; FILE *fin, *fout; short input[MAX_FRAME_SIZE]; int frame_size; int quiet=0; int vbr_enabled=0; int abr_enabled=0; int vad_enabled=0; int dtx_enabled=0; int nbBytes; const SpeexMode *mode=NULL; int modeID = -1; void *st; SpeexBits bits; char cbits[MAX_FRAME_BYTES]; struct option long_options[] = { {"wideband", no_argument, NULL, 0}, {"ultra-wideband", no_argument, NULL, 0}, {"narrowband", no_argument, NULL, 0}, {"vbr", no_argument, NULL, 0}, {"abr", required_argument, NULL, 0}, {"vad", no_argument, NULL, 0}, {"dtx", no_argument, NULL, 0}, {"quality", required_argument, NULL, 0}, {"bitrate", required_argument, NULL, 0}, {"nframes", required_argument, NULL, 0}, {"comp", required_argument, NULL, 0}, {"denoise", no_argument, NULL, 0}, {"agc", no_argument, NULL, 0}, {"help", no_argument, NULL, 0}, {"quiet", no_argument, NULL, 0}, {"le", no_argument, NULL, 0}, {"be", no_argument, NULL, 0}, {"8bit", no_argument, NULL, 0}, {"16bit", no_argument, NULL, 0}, {"stereo", no_argument, NULL, 0}, {"rate", required_argument, NULL, 0}, {"version", no_argument, NULL, 0}, {"version-short", no_argument, NULL, 0}, {"comment", required_argument, NULL, 0}, {"author", required_argument, NULL, 0}, {"title", required_argument, NULL, 0}, {0, 0, 0, 0} }; int print_bitrate=0; int rate=0, size; int chan=1; int fmt=16; int quality=-1; float vbr_quality=-1; int lsb=1; ogg_stream_state os; ogg_page og; ogg_packet op; int bytes_written=0, ret, result; int id=-1; SpeexHeader header; int nframes=1; int complexity=3; char *vendor_string = "Encoded with Speex " SPEEX_VERSION; char *comments; int comments_length; int close_in=0, close_out=0; int eos=0; int bitrate=0; double cumul_bits=0, enc_frames=0; char first_bytes[12]; int wave_input=0; int tmp; SpeexPreprocessState *preprocess = NULL; int denoise_enabled=0, agc_enabled=0; int lookahead = 0; comment_init(&comments, &comments_length, vendor_string); /*Process command-line options*/ while(1) { c = getopt_long (argc, argv, "nwuhvV", long_options, &option_index); if (c==-1) break; switch(c) { case 0: if (strcmp(long_options[option_index].name,"narrowband")==0) { modeID = SPEEX_MODEID_NB; } else if (strcmp(long_options[option_index].name,"wideband")==0) { modeID = SPEEX_MODEID_WB; } else if (strcmp(long_options[option_index].name,"ultra-wideband")==0) { modeID = SPEEX_MODEID_UWB; } else if (strcmp(long_options[option_index].name,"vbr")==0) { vbr_enabled=1; } else if (strcmp(long_options[option_index].name,"abr")==0) { abr_enabled=atoi(optarg); if (!abr_enabled) { fprintf (stderr, "Invalid ABR value: %d\n", abr_enabled); exit(1); } } else if (strcmp(long_options[option_index].name,"vad")==0) { vad_enabled=1; } else if (strcmp(long_options[option_index].name,"dtx")==0) { dtx_enabled=1; } else if (strcmp(long_options[option_index].name,"quality")==0) { quality = atoi (optarg); vbr_quality=atof(optarg); } else if (strcmp(long_options[option_index].name,"bitrate")==0) { bitrate = atoi (optarg); } else if (strcmp(long_options[option_index].name,"nframes")==0) { nframes = atoi (optarg); if (nframes<1) nframes=1; if (nframes>10) nframes=10; } else if (strcmp(long_options[option_index].name,"comp")==0) { complexity = atoi (optarg); } else if (strcmp(long_options[option_index].name,"denoise")==0) { denoise_enabled=1; } else if (strcmp(long_options[option_index].name,"agc")==0) { agc_enabled=1; } else if (strcmp(long_options[option_index].name,"help")==0) { usage(); exit(0); } else if (strcmp(long_options[option_index].name,"quiet")==0) { quiet = 1; } else if (strcmp(long_options[option_index].name,"version")==0) { version(); exit(0); } else if (strcmp(long_options[option_index].name,"version-short")==0) { version_short(); exit(0); } else if (strcmp(long_options[option_index].name,"le")==0) { lsb=1; } else if (strcmp(long_options[option_index].name,"be")==0) { lsb=0; } else if (strcmp(long_options[option_index].name,"8bit")==0) { fmt=8; } else if (strcmp(long_options[option_index].name,"16bit")==0) { fmt=16; } else if (strcmp(long_options[option_index].name,"stereo")==0) { chan=2; } else if (strcmp(long_options[option_index].name,"rate")==0) { rate=atoi (optarg); } else if (strcmp(long_options[option_index].name,"comment")==0) { if (!strchr(optarg, '=')) { fprintf (stderr, "Invalid comment: %s\n", optarg); fprintf (stderr, "Comments must be of the form name=value\n"); exit(1); } comment_add(&comments, &comments_length, NULL, optarg); } else if (strcmp(long_options[option_index].name,"author")==0) { comment_add(&comments, &comments_length, "author=", optarg); } else if (strcmp(long_options[option_index].name,"title")==0) { comment_add(&comments, &comments_length, "title=", optarg); } break; case 'n': modeID = SPEEX_MODEID_NB; break; case 'h': usage(); exit(0); break; case 'v': version(); exit(0); break; case 'V': print_bitrate=1; break; case 'w': modeID = SPEEX_MODEID_WB; break; case 'u': modeID = SPEEX_MODEID_UWB; break; case '?': usage(); exit(1); break; } } if (argc-optind!=2) { usage(); exit(1); } inFile=argv[optind]; outFile=argv[optind+1]; /*Initialize Ogg stream struct*/ srand(time(NULL)); if (ogg_stream_init(&os, rand())==-1) { fprintf(stderr,"Error: stream init failed\n"); exit(1); } if (strcmp(inFile, "-")==0) { #if defined WIN32 || defined _WIN32 _setmode(_fileno(stdin), _O_BINARY); #endif fin=stdin; } else { fin = fopen(inFile, "rb"); if (!fin) { perror(inFile); exit(1); } close_in=1; } { fread(first_bytes, 1, 12, fin); if (strncmp(first_bytes,"RIFF",4)==0 && strncmp(first_bytes,"RIFF",4)==0) { if (read_wav_header(fin, &rate, &chan, &fmt, &size)==-1) exit(1); wave_input=1; lsb=1; /* CHECK: exists big-endian .wav ?? */ } } if (modeID==-1 && !rate) { /* By default, use narrowband/8 kHz */ modeID = SPEEX_MODEID_NB; rate=8000; } else if (modeID!=-1 && rate) { if (rate>48000) { fprintf (stderr, "Error: sampling rate too high: %d Hz, try down-sampling\n", rate); exit(1); } else if (rate>25000) { if (modeID != SPEEX_MODEID_UWB) { fprintf (stderr, "Warning: Trying to encode in %s at %d Hz. I'll do it but I suggest you try ultra-wideband instead\n", mode->modeName , rate); } } else if (rate>12500) { if (modeID != SPEEX_MODEID_WB) { fprintf (stderr, "Warning: Trying to encode in %s at %d Hz. I'll do it but I suggest you try wideband instead\n", mode->modeName , rate); } } else if (rate>=6000) { if (modeID != SPEEX_MODEID_NB) { fprintf (stderr, "Warning: Trying to encode in %s at %d Hz. I'll do it but I suggest you try narrowband instead\n", mode->modeName , rate); } } else { fprintf (stderr, "Error: sampling rate too low: %d Hz\n", rate); exit(1); } } else if (modeID==-1) { if (rate>48000) { fprintf (stderr, "Error: sampling rate too high: %d Hz, try down-sampling\n", rate); exit(1); } else if (rate>25000) { modeID = SPEEX_MODEID_UWB; } else if (rate>12500) { modeID = SPEEX_MODEID_WB; } else if (rate>=6000) { modeID = SPEEX_MODEID_NB; } else { fprintf (stderr, "Error: Sampling rate too low: %d Hz\n", rate); exit(1); } } else if (!rate) { if (modeID == SPEEX_MODEID_NB) rate=8000; else if (modeID == SPEEX_MODEID_WB) rate=16000; else if (modeID == SPEEX_MODEID_UWB) rate=32000; } if (!quiet) if (rate!=8000 && rate!=16000 && rate!=32000) fprintf (stderr, "Warning: Speex is only optimized for 8, 16 and 32 kHz. It will still work at %d Hz but your mileage may vary\n", rate); mode = speex_lib_get_mode (modeID); speex_init_header(&header, rate, 1, mode); header.frames_per_packet=nframes; header.vbr=vbr_enabled; header.nb_channels = chan; { char *st_string="mono"; if (chan==2) st_string="stereo"; if (!quiet) fprintf (stderr, "Encoding %d Hz audio using %s mode (%s)\n", header.rate, mode->modeName, st_string); } /*fprintf (stderr, "Encoding %d Hz audio at %d bps using %s mode\n", header.rate, mode->bitrate, mode->modeName);*/ /*Initialize Speex encoder*/ st = speex_encoder_init(mode); if (strcmp(outFile,"-")==0) { #if defined WIN32 || defined _WIN32 _setmode(_fileno(stdout), _O_BINARY); #endif fout=stdout; } else { fout = fopen(outFile, "wb"); if (!fout) { perror(outFile); exit(1); } close_out=1; } speex_encoder_ctl(st, SPEEX_GET_FRAME_SIZE, &frame_size); speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &complexity); speex_encoder_ctl(st, SPEEX_SET_SAMPLING_RATE, &rate); if (quality >= 0) { if (vbr_enabled) speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &vbr_quality); else speex_encoder_ctl(st, SPEEX_SET_QUALITY, &quality); } if (bitrate) { if (quality >= 0 && vbr_enabled) fprintf (stderr, "Warning: --bitrate option is overriding --quality\n"); speex_encoder_ctl(st, SPEEX_SET_BITRATE, &bitrate); } if (vbr_enabled) { tmp=1; speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); } else if (vad_enabled) { tmp=1; speex_encoder_ctl(st, SPEEX_SET_VAD, &tmp); } if (dtx_enabled) speex_encoder_ctl(st, SPEEX_SET_DTX, &tmp); if (dtx_enabled && !(vbr_enabled || abr_enabled || vad_enabled)) { fprintf (stderr, "Warning: --dtx is useless without --vad, --vbr or --abr\n"); } else if ((vbr_enabled || abr_enabled) && (vad_enabled)) { fprintf (stderr, "Warning: --vad is already implied by --vbr or --abr\n"); } if (abr_enabled) { speex_encoder_ctl(st, SPEEX_SET_ABR, &abr_enabled); } speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead); if (denoise_enabled || agc_enabled) { preprocess = speex_preprocess_state_init(frame_size, rate); speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DENOISE, &denoise_enabled); speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC, &agc_enabled); lookahead += frame_size; } /*Write header*/ { op.packet = (unsigned char *)speex_header_to_packet(&header, (int*)&(op.bytes)); op.b_o_s = 1; op.e_o_s = 0; op.granulepos = 0; op.packetno = 0; ogg_stream_packetin(&os, &op); free(op.packet); op.packet = (unsigned char *)comments; op.bytes = comments_length; op.b_o_s = 0; op.e_o_s = 0; op.granulepos = 0; op.packetno = 1; ogg_stream_packetin(&os, &op); while((result = ogg_stream_flush(&os, &og))) { if(!result) break; ret = oe_write_page(&og, fout); if(ret != og.header_len + og.body_len) { fprintf (stderr,"Error: failed writing header to output stream\n"); exit(1); } else bytes_written += ret; } } free(comments); speex_bits_init(&bits); if (!wave_input) { nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, first_bytes, NULL); } else { nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size); } if (nb_samples==0) eos=1; total_samples += nb_samples; nb_encoded = -lookahead; /*Main encoding loop (one frame per iteration)*/ while (!eos || total_samples>nb_encoded) { id++; /*Encode current frame*/ if (chan==2) speex_encode_stereo_int(input, frame_size, &bits); if (preprocess) speex_preprocess(preprocess, input, NULL); speex_encode_int(st, input, &bits); nb_encoded += frame_size; if (print_bitrate) { int tmp; char ch=13; speex_encoder_ctl(st, SPEEX_GET_BITRATE, &tmp); fputc (ch, stderr); cumul_bits += tmp; enc_frames += 1; if (!quiet) { if (vad_enabled || vbr_enabled || abr_enabled) fprintf (stderr, "Bitrate is use: %d bps (average %d bps) ", tmp, (int)(cumul_bits/enc_frames)); else fprintf (stderr, "Bitrate is use: %d bps ", tmp); } } if (wave_input) { nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size); } else { nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, NULL); } if (nb_samples==0) { eos=1; } if (eos && total_samples<=nb_encoded) op.e_o_s = 1; else op.e_o_s = 0; total_samples += nb_samples; if ((id+1)%nframes!=0) continue; speex_bits_insert_terminator(&bits); nbBytes = speex_bits_write(&bits, cbits, MAX_FRAME_BYTES); speex_bits_reset(&bits); op.packet = (unsigned char *)cbits; op.bytes = nbBytes; op.b_o_s = 0; /*Is this redundent?*/ if (eos && total_samples<=nb_encoded) op.e_o_s = 1; else op.e_o_s = 0; op.granulepos = (id+1)*frame_size-lookahead; if (op.granulepos>total_samples) op.granulepos = total_samples; /*printf ("granulepos: %d %d %d %d %d %d\n", (int)op.granulepos, id, nframes, lookahead, 5, 6);*/ op.packetno = 2+id/nframes; ogg_stream_packetin(&os, &op); /*Write all new pages (most likely 0 or 1)*/ while (ogg_stream_pageout(&os,&og)) { ret = oe_write_page(&og, fout); if(ret != og.header_len + og.body_len) { fprintf (stderr,"Error: failed writing header to output stream\n"); exit(1); } else bytes_written += ret; } } if ((id+1)%nframes!=0) { while ((id+1)%nframes!=0) { id++; speex_bits_pack(&bits, 15, 5); } nbBytes = speex_bits_write(&bits, cbits, MAX_FRAME_BYTES); op.packet = (unsigned char *)cbits; op.bytes = nbBytes; op.b_o_s = 0; op.e_o_s = 1; op.granulepos = (id+1)*frame_size-lookahead; if (op.granulepos>total_samples) op.granulepos = total_samples; op.packetno = 2+id/nframes; ogg_stream_packetin(&os, &op); } /*Flush all pages left to be written*/ while (ogg_stream_flush(&os, &og)) { ret = oe_write_page(&og, fout); if(ret != og.header_len + og.body_len) { fprintf (stderr,"Error: failed writing header to output stream\n"); exit(1); } else bytes_written += ret; } speex_encoder_destroy(st); speex_bits_destroy(&bits); ogg_stream_clear(&os); if (close_in) fclose(fin); if (close_out) fclose(fout); return 0; }
int main(int argc,char *argv[]){ int c,long_option_index,ret; ogg_stream_state to; /* take physical pages, weld into a logical stream of packets */ ogg_stream_state vo; /* take physical pages, weld into a logical stream of packets */ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ ogg_packet op; /* one raw packet of data for decode */ theora_state td; theora_info ti; theora_comment tc; vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ vorbis_comment vc; /* struct that stores all the user comments */ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ vorbis_block vb; /* local working space for packet->PCM decode */ int audioflag=0; int videoflag=0; int akbps=0; int vkbps=0; ogg_int64_t audio_bytesout=0; ogg_int64_t video_bytesout=0; double timebase; FILE* outfile = stdout; #ifdef _WIN32 # ifdef THEORA_PERF_DATA LARGE_INTEGER start_time; LARGE_INTEGER final_time; LONGLONG elapsed_ticks; LARGE_INTEGER ticks_per_second; LONGLONG elapsed_secs; LONGLONG elapsed_sec_mod; double elapsed_secs_dbl ; # endif /* We need to set stdin/stdout to binary mode. Damn windows. */ /* if we were reading/writing a file, it would also need to in binary mode, eg, fopen("file.wav","wb"); */ /* Beware the evil ifdef. We avoid these where we can, but this one we cannot. Don't add any more, you'll probably go to hell if you do. */ _setmode( _fileno( stdin ), _O_BINARY ); _setmode( _fileno( stdout ), _O_BINARY ); #endif while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){ switch(c){ case 'o': outfile=fopen(optarg,"wb"); if(outfile==NULL){ fprintf(stderr,"Unable to open output file '%s'\n", optarg); exit(1); } break;; case 'a': audio_q=atof(optarg)*.099; if(audio_q<-.1 || audio_q>1){ fprintf(stderr,"Illegal audio quality (choose -1 through 10)\n"); exit(1); } audio_r=-1; break; case 'v': video_q=rint(atof(optarg)*6.3); if(video_q<0 || video_q>63){ fprintf(stderr,"Illegal video quality (choose 0 through 10)\n"); exit(1); } video_r=0; break; case 'A': audio_r=atof(optarg)*1000; if(audio_q<0){ fprintf(stderr,"Illegal audio quality (choose > 0 please)\n"); exit(1); } audio_q=-99; break; case 'V': video_r=rint(atof(optarg)*1000); if(video_r<45000 || video_r>2000000){ fprintf(stderr,"Illegal video bitrate (choose 45kbps through 2000kbps)\n"); exit(1); } video_q=0; break; case 's': video_an=rint(atof(optarg)); break; case 'S': video_ad=rint(atof(optarg)); break; case 'f': video_hzn=rint(atof(optarg)); break; case 'F': video_hzd=rint(atof(optarg)); break; default: usage(); } } while(optind<argc){ /* assume that anything following the options must be a filename */ id_file(argv[optind]); optind++; } #ifdef THEORA_PERF_DATA # ifdef WIN32 QueryPerformanceCounter(&start_time); # endif #endif /* yayness. Set up Ogg output stream */ srand(time(NULL)); { /* need two inequal serial numbers */ int serial1, serial2; serial1 = rand(); serial2 = rand(); if (serial1 == serial2) serial2++; ogg_stream_init(&to,serial1); ogg_stream_init(&vo,serial2); } /* Set up Theora encoder */ if(!video){ fprintf(stderr,"No video files submitted for compression?\n"); exit(1); } /* Theora has a divisible-by-sixteen restriction for the encoded video size */ /* scale the frame size up to the nearest /16 and calculate offsets */ video_x=((frame_x + 15) >>4)<<4; video_y=((frame_y + 15) >>4)<<4; /* We force the offset to be even. This ensures that the chroma samples align properly with the luma samples. */ frame_x_offset=((video_x-frame_x)/2)&~1; frame_y_offset=((video_y-frame_y)/2)&~1; theora_info_init(&ti); ti.width=video_x; ti.height=video_y; ti.frame_width=frame_x; ti.frame_height=frame_y; ti.offset_x=frame_x_offset; ti.offset_y=frame_y_offset; ti.fps_numerator=video_hzn; ti.fps_denominator=video_hzd; ti.aspect_numerator=video_an; ti.aspect_denominator=video_ad; ti.colorspace=OC_CS_UNSPECIFIED; ti.pixelformat=OC_PF_420; ti.target_bitrate=video_r; ti.quality=video_q; ti.dropframes_p=0; ti.quick_p=1; ti.keyframe_auto_p=1; ti.keyframe_frequency=64; ti.keyframe_frequency_force=64; ti.keyframe_data_target_bitrate=video_r*1.5; ti.keyframe_auto_threshold=80; ti.keyframe_mindistance=8; ti.noise_sensitivity=1; theora_encode_init(&td,&ti); theora_info_clear(&ti); /* initialize Vorbis too, assuming we have audio to compress. */ if(audio){ vorbis_info_init(&vi); if(audio_q>-99) ret = vorbis_encode_init_vbr(&vi,audio_ch,audio_hz,audio_q); else ret = vorbis_encode_init(&vi,audio_ch,audio_hz,-1,audio_r,-1); if(ret){ fprintf(stderr,"The Vorbis encoder could not set up a mode according to\n" "the requested quality or bitrate.\n\n"); exit(1); } vorbis_comment_init(&vc); vorbis_analysis_init(&vd,&vi); vorbis_block_init(&vd,&vb); } /* write the bitstream header packets with proper page interleave */ /* first packet will get its own page automatically */ theora_encode_header(&td,&op); ogg_stream_packetin(&to,&op); if(ogg_stream_pageout(&to,&og)!=1){ fprintf(stderr,"Internal Ogg library error.\n"); exit(1); } fwrite(og.header,1,og.header_len,outfile); fwrite(og.body,1,og.body_len,outfile); /* create the remaining theora headers */ theora_comment_init(&tc); theora_encode_comment(&tc,&op); ogg_stream_packetin(&to,&op); /*theora_encode_comment() doesn't take a theora_state parameter, so it has to allocate its own buffer to pass back the packet data. If we don't free it here, we'll leak. libogg2 makes this much cleaner: the stream owns the buffer after you call packetin in libogg2, but this is not true in libogg1.*/ free(op.packet); theora_encode_tables(&td,&op); ogg_stream_packetin(&to,&op); if(audio){ ogg_packet header; ogg_packet header_comm; ogg_packet header_code; vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code); ogg_stream_packetin(&vo,&header); /* automatically placed in its own page */ if(ogg_stream_pageout(&vo,&og)!=1){ fprintf(stderr,"Internal Ogg library error.\n"); exit(1); } fwrite(og.header,1,og.header_len,outfile); fwrite(og.body,1,og.body_len,outfile); /* remaining vorbis header packets */ ogg_stream_packetin(&vo,&header_comm); ogg_stream_packetin(&vo,&header_code); } /* Flush the rest of our headers. This ensures the actual data in each stream will start on a new page, as per spec. */ while(1){ int result = ogg_stream_flush(&to,&og); if(result<0){ /* can't get here */ fprintf(stderr,"Internal Ogg library error.\n"); exit(1); } if(result==0)break; fwrite(og.header,1,og.header_len,outfile); fwrite(og.body,1,og.body_len,outfile); } if(audio){ while(1){ int result=ogg_stream_flush(&vo,&og); if(result<0){ /* can't get here */ fprintf(stderr,"Internal Ogg library error.\n"); exit(1); } if(result==0)break; fwrite(og.header,1,og.header_len,outfile); fwrite(og.body,1,og.body_len,outfile); } } /* setup complete. Raw processing loop */ fprintf(stderr,"Compressing....\n"); while(1){ ogg_page audiopage; ogg_page videopage; /* is there an audio page flushed? If not, fetch one if possible */ audioflag=fetch_and_process_audio(audio,&audiopage,&vo,&vd,&vb,audioflag); /* is there a video page flushed? If not, fetch one if possible */ videoflag=fetch_and_process_video(video,&videopage,&to,&td,videoflag); /* no pages of either? Must be end of stream. */ if(!audioflag && !videoflag)break; /* which is earlier; the end of the audio page or the end of the video page? Flush the earlier to stream */ { int audio_or_video=-1; double audiotime= audioflag?vorbis_granule_time(&vd,ogg_page_granulepos(&audiopage)):-1; double videotime= videoflag?theora_granule_time(&td,ogg_page_granulepos(&videopage)):-1; if(!audioflag){ audio_or_video=1; } else if(!videoflag) { audio_or_video=0; } else { if(audiotime<videotime) audio_or_video=0; else audio_or_video=1; } if(audio_or_video==1){ /* flush a video page */ video_bytesout+=fwrite(videopage.header,1,videopage.header_len,outfile); video_bytesout+=fwrite(videopage.body,1,videopage.body_len,outfile); videoflag=0; timebase=videotime; }else{ /* flush an audio page */ audio_bytesout+=fwrite(audiopage.header,1,audiopage.header_len,outfile); audio_bytesout+=fwrite(audiopage.body,1,audiopage.body_len,outfile); audioflag=0; timebase=audiotime; } { int hundredths=timebase*100-(long)timebase*100; int seconds=(long)timebase%60; int minutes=((long)timebase/60)%60; int hours=(long)timebase/3600; if(audio_or_video) vkbps=rint(video_bytesout*8./timebase*.001); else akbps=rint(audio_bytesout*8./timebase*.001); fprintf(stderr, "\r %d:%02d:%02d.%02d audio: %dkbps video: %dkbps ", hours,minutes,seconds,hundredths,akbps,vkbps); } } } /* clear out state */ if(audio){ ogg_stream_clear(&vo); vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); } if(video){ ogg_stream_clear(&to); theora_clear(&td); } if(outfile && outfile!=stdout)fclose(outfile); fprintf(stderr,"\r \ndone.\n\n"); #ifdef THEORA_PERF_DATA # ifdef WIN32 QueryPerformanceCounter(&final_time); elapsed_ticks = final_time.QuadPart - start_time.QuadPart; ticks_per_second; QueryPerformanceFrequency(&ticks_per_second); elapsed_secs = elapsed_ticks / ticks_per_second.QuadPart; elapsed_sec_mod = elapsed_ticks % ticks_per_second.QuadPart; elapsed_secs_dbl = elapsed_secs; elapsed_secs_dbl += ((double)elapsed_sec_mod / (double)ticks_per_second.QuadPart); printf("Encode time = %lld ticks\n", elapsed_ticks); printf("~%lld and %lld / %lld seconds\n", elapsed_secs, elapsed_sec_mod, ticks_per_second.QuadPart); printf("~%Lf seconds\n", elapsed_secs_dbl); # endif #endif return(0); }
static stream_processor * find_stream_processor (stream_set *set, ogg_page *page) { uint32_t serial = ogg_page_serialno (page) ; int i, invalid = 0 ; stream_processor *stream ; for (i = 0 ; i < set->used ; i++) { if (serial == set->streams [i].serial) { /* We have a match! */ stream = & (set->streams [i]) ; set->in_headers = 0 ; /* if we have detected EOS, then this can't occur here. */ if (stream->end) { stream->isillegal = 1 ; return stream ; } stream->isnew = 0 ; stream->end = ogg_page_eos (page) ; stream->serial = serial ; return stream ; } ; } ; /* If there are streams open, and we've reached the end of the ** headers, then we can't be starting a new stream. ** XXX: might this sometimes catch ok streams if EOS flag is missing, ** but the stream is otherwise ok? */ if (streams_open (set) && !set->in_headers) invalid = 1 ; set->in_headers = 1 ; if (set->allocated < set->used) stream = &set->streams [set->used] ; else { set->allocated += 5 ; set->streams = realloc (set->streams, sizeof (stream_processor) * set->allocated) ; stream = &set->streams [set->used] ; } ; set->used++ ; stream->isnew = 1 ; stream->isillegal = invalid ; { int res ; ogg_packet packet ; /* We end up processing the header page twice, but that's ok. */ ogg_stream_init (&stream->ostream, serial) ; ogg_stream_pagein (&stream->ostream, page) ; res = ogg_stream_packetout (&stream->ostream, &packet) ; if (res <= 0) return NULL ; else if (packet.bytes >= 7 && memcmp (packet.packet, "\x01vorbis", 7) == 0) { stream->lastgranulepos = 0 ; vorbis_comment_init (&stream->vcomment) ; vorbis_info_init (&stream->vinfo) ; } ; res = ogg_stream_packetout (&stream->ostream, &packet) ; /* re-init, ready for processing */ ogg_stream_clear (&stream->ostream) ; ogg_stream_init (&stream->ostream, serial) ; } stream->end = ogg_page_eos (page) ; stream->serial = serial ; return stream ; } /* find_stream_processor */
/* The following function is basically a hacked version of the code in * examples/decoder_example.c */ void read_vorbis_data_or_die (const char *filename, int srate, float * data, int count) { ogg_sync_state oy; ogg_stream_state os; ogg_page og; ogg_packet op; vorbis_info vi; vorbis_comment vc; vorbis_dsp_state vd; vorbis_block vb; FILE *file; char *buffer; int bytes; int eos = 0; int i; int read_total = 0 ; if ((file = fopen (filename, "rb")) == NULL) { printf("\n\nError : fopen failed : %s\n", strerror (errno)) ; exit (1) ; } ogg_sync_init (&oy); { /* fragile! Assumes all of our headers will fit in the first 8kB, which currently they will */ buffer = ogg_sync_buffer (&oy,8192); bytes = fread (buffer,1,8192,file); ogg_sync_wrote (&oy,bytes); if(ogg_sync_pageout (&oy,&og) != 1) { if(bytes < 8192) { printf ("Out of data.\n") ; goto done_decode ; } fprintf (stderr,"Input does not appear to be an Ogg bitstream.\n"); exit (1); } ogg_stream_init (&os,ogg_page_serialno(&og)); vorbis_info_init (&vi); vorbis_comment_init (&vc); if (ogg_stream_pagein (&os,&og) < 0) { fprintf (stderr,"Error reading first page of Ogg bitstream data.\n"); exit (1); } if (ogg_stream_packetout(&os,&op) != 1) { fprintf (stderr,"Error reading initial header packet.\n"); exit (1); } if (vorbis_synthesis_headerin (&vi,&vc,&op) < 0) { fprintf (stderr,"This Ogg bitstream does not contain Vorbis " "audio data.\n"); exit (1); } i = 0; while ( i < 2) { while (i < 2) { int result = ogg_sync_pageout (&oy,&og); if(result == 0) break; if(result==1) { ogg_stream_pagein(&os,&og); while (i < 2) { result = ogg_stream_packetout (&os,&op); if (result == 0) break; if (result < 0) { fprintf (stderr,"Corrupt secondary header. Exiting.\n"); exit(1); } vorbis_synthesis_headerin (&vi,&vc,&op); i++; } } } buffer = ogg_sync_buffer (&oy,4096); bytes = fread (buffer,1,4096,file); if (bytes == 0 && i < 2) { fprintf (stderr,"End of file before finding all Vorbis headers!\n"); exit (1); } ogg_sync_wrote (&oy,bytes); } if (vi.rate != srate) { printf ("\n\nError : File '%s' has sample rate of %ld when it should be %d.\n\n", filename, vi.rate, srate); exit (1) ; } vorbis_synthesis_init (&vd,&vi); vorbis_block_init (&vd,&vb); while(!eos) { while (!eos) { int result = ogg_sync_pageout (&oy,&og); if (result == 0) break; if (result < 0) { fprintf (stderr,"Corrupt or missing data in bitstream; " "continuing...\n"); } else { ogg_stream_pagein (&os,&og); while (1) { result = ogg_stream_packetout (&os,&op); if (result == 0) break; if (result < 0) { /* no reason to complain; already complained above */ } else { float **pcm; int samples; if (vorbis_synthesis (&vb,&op) == 0) vorbis_synthesis_blockin(&vd,&vb); while ((samples = vorbis_synthesis_pcmout (&vd,&pcm)) > 0 && read_total < count) { int bout = samples < count ? samples : count; bout = read_total + bout > count ? count - read_total : bout; memcpy (data + read_total, pcm[0], bout * sizeof (float)) ; vorbis_synthesis_read (&vd,bout); read_total += bout ; } } } if (ogg_page_eos (&og)) eos = 1; } } if (!eos) { buffer = ogg_sync_buffer (&oy,4096); bytes = fread (buffer,1,4096,file); ogg_sync_wrote (&oy,bytes); if (bytes == 0) eos = 1; } } ogg_stream_clear (&os); vorbis_block_clear (&vb); vorbis_dsp_clear (&vd); vorbis_comment_clear (&vc); vorbis_info_clear (&vi); } done_decode: /* OK, clean up the framer */ ogg_sync_clear (&oy); fclose (file) ; }
static int vorbis_read_header (SF_PRIVATE *psf, int log_data) { OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; char *buffer ; int bytes ; int i, nn ; odata->eos = 0 ; /* Weird stuff happens if these aren't called. */ ogg_stream_reset (&odata->ostream) ; ogg_sync_reset (&odata->osync) ; /* ** Grab some data at the head of the stream. We want the first page ** (which is guaranteed to be small and only contain the Vorbis ** stream initial header) We need the first page to get the stream ** serialno. */ /* Expose the buffer */ buffer = ogg_sync_buffer (&odata->osync, 4096L) ; /* Grab the part of the header that has already been read. */ memcpy (buffer, psf->header, psf->headindex) ; bytes = psf->headindex ; /* Submit a 4k block to libvorbis' Ogg layer */ bytes += psf_fread (buffer + psf->headindex, 1, 4096 - psf->headindex, psf) ; ogg_sync_wrote (&odata->osync, bytes) ; /* Get the first page. */ if ((nn = ogg_sync_pageout (&odata->osync, &odata->opage)) != 1) { /* Have we simply run out of data? If so, we're done. */ if (bytes < 4096) return 0 ; /* Error case. Must not be Vorbis data */ psf_log_printf (psf, "Input does not appear to be an Ogg bitstream.\n") ; return SFE_MALFORMED_FILE ; } ; /* ** Get the serial number and set up the rest of decode. ** Serialno first ; use it to set up a logical stream. */ ogg_stream_clear (&odata->ostream) ; ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ; if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0) { /* Error ; stream version mismatch perhaps. */ psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ; return SFE_MALFORMED_FILE ; } ; if (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1) { /* No page? must not be vorbis. */ psf_log_printf (psf, "Error reading initial header packet.\n") ; return SFE_MALFORMED_FILE ; } ; /* ** This function (vorbis_read_header) gets called multiple times, so the OGG ** and vorbis structs have to be cleared every time we pass through to ** prevent memory leaks. */ vorbis_block_clear (&vdata->vblock) ; vorbis_dsp_clear (&vdata->vdsp) ; vorbis_comment_clear (&vdata->vcomment) ; vorbis_info_clear (&vdata->vinfo) ; /* ** Extract the initial header from the first page and verify that the ** Ogg bitstream is in fact Vorbis data. ** ** I handle the initial header first instead of just having the code ** read all three Vorbis headers at once because reading the initial ** header is an easy way to identify a Vorbis bitstream and it's ** useful to see that functionality seperated out. */ vorbis_info_init (&vdata->vinfo) ; vorbis_comment_init (&vdata->vcomment) ; if (vorbis_synthesis_headerin (&vdata->vinfo, &vdata->vcomment, &odata->opacket) < 0) { /* Error case ; not a vorbis header. */ psf_log_printf (psf, "Found Vorbis in stream header, but vorbis_synthesis_headerin failed.\n") ; return SFE_MALFORMED_FILE ; } ; /* ** Common Ogg metadata fields? ** TITLE, VERSION, ALBUM, TRACKNUMBER, ARTIST, PERFORMER, COPYRIGHT, LICENSE, ** ORGANIZATION, DESCRIPTION, GENRE, DATE, LOCATION, CONTACT, ISRC, */ if (log_data) { int k ; for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++) { char *dd ; dd = vorbis_comment_query (&vdata->vcomment, vorbis_metatypes [k].name, 0) ; if (dd == NULL) continue ; psf_store_string (psf, vorbis_metatypes [k].id, dd) ; } ; } ; /* ** At this point, we're sure we're Vorbis. We've set up the logical (Ogg) ** bitstream decoder. Get the comment and codebook headers and set up the ** Vorbis decoder. ** ** The next two packets in order are the comment and codebook headers. ** They're likely large and may span multiple pages. Thus we reead ** and submit data until we get our two pacakets, watching that no ** pages are missing. If a page is missing, error out ; losing a ** header page is the only place where missing data is fatal. */ i = 0 ; /* Count of number of packets read */ while (i < 2) { int result = ogg_sync_pageout (&odata->osync, &odata->opage) ; if (result == 0) { /* Need more data */ buffer = ogg_sync_buffer (&odata->osync, 4096) ; bytes = psf_fread (buffer, 1, 4096, psf) ; if (bytes == 0 && i < 2) { psf_log_printf (psf, "End of file before finding all Vorbis headers!\n") ; return SFE_MALFORMED_FILE ; } ; nn = ogg_sync_wrote (&odata->osync, bytes) ; } else if (result == 1) { /* ** Don't complain about missing or corrupt data yet. We'll ** catch it at the packet output phase. ** ** We can ignore any errors here as they'll also become apparent ** at packetout. */ nn = ogg_stream_pagein (&odata->ostream, &odata->opage) ; while (i < 2) { result = ogg_stream_packetout (&odata->ostream, &odata->opacket) ; if (result == 0) break ; if (result < 0) { /* Uh oh ; data at some point was corrupted or missing! ** We can't tolerate that in a header. Die. */ psf_log_printf (psf, "Corrupt secondary header. Exiting.\n") ; return SFE_MALFORMED_FILE ; } ; vorbis_synthesis_headerin (&vdata->vinfo, &vdata->vcomment, &odata->opacket) ; i++ ; } ; } ; } ; if (log_data) { int printed_metadata_msg = 0 ; int k ; psf_log_printf (psf, "Bitstream is %d channel, %D Hz\n", vdata->vinfo.channels, vdata->vinfo.rate) ; psf_log_printf (psf, "Encoded by : %s\n", vdata->vcomment.vendor) ; /* Throw the comments plus a few lines about the bitstream we're decoding. */ for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++) { char *dd ; dd = vorbis_comment_query (&vdata->vcomment, vorbis_metatypes [k].name, 0) ; if (dd == NULL) continue ; if (printed_metadata_msg == 0) { psf_log_printf (psf, "Metadata :\n") ; printed_metadata_msg = 1 ; } ; psf_store_string (psf, vorbis_metatypes [k].id, dd) ; psf_log_printf (psf, " %-10s : %s\n", vorbis_metatypes [k].name, dd) ; } ; psf_log_printf (psf, "End\n") ; } ; psf->sf.samplerate = vdata->vinfo.rate ; psf->sf.channels = vdata->vinfo.channels ; psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; /* OK, got and parsed all three headers. Initialize the Vorbis ** packet->PCM decoder. ** Central decode state. */ vorbis_synthesis_init (&vdata->vdsp, &vdata->vinfo) ; /* Local state for most of the decode so multiple block decodes can ** proceed in parallel. We could init multiple vorbis_block structures ** for vd here. */ vorbis_block_init (&vdata->vdsp, &vdata->vblock) ; vdata->loc = 0 ; return 0 ; } /* vorbis_read_header */
static int vorbis_write_header (SF_PRIVATE *psf, int UNUSED (calc_length)) { OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; int k, ret ; vorbis_info_init (&vdata->vinfo) ; /* The style of encoding should be selectable here, VBR quality mode. */ ret = vorbis_encode_init_vbr (&vdata->vinfo, psf->sf.channels, psf->sf.samplerate, vdata->quality) ; #if 0 ret = vorbis_encode_init (&vdata->vinfo, psf->sf.channels, psf->sf.samplerate, -1, 128000, -1) ; /* average bitrate mode */ ret = ( vorbis_encode_setup_managed (&vdata->vinfo, psf->sf.channels, psf->sf.samplerate, -1, 128000, -1) || vorbis_encode_ctl (&vdata->vinfo, OV_ECTL_RATEMANAGE_AVG, NULL) || vorbis_encode_setup_init (&vdata->vinfo) ) ; #endif if (ret) return SFE_BAD_OPEN_FORMAT ; vdata->loc = 0 ; /* add a comment */ vorbis_comment_init (&vdata->vcomment) ; vorbis_comment_add_tag (&vdata->vcomment, "ENCODER", "libsndfile") ; for (k = 0 ; k < SF_MAX_STRINGS ; k++) { const char * name ; if (psf->strings.data [k].type == 0) break ; switch (psf->strings.data [k].type) { case SF_STR_TITLE : name = "TITLE" ; break ; case SF_STR_COPYRIGHT : name = "COPYRIGHT" ; break ; case SF_STR_SOFTWARE : name = "SOFTWARE" ; break ; case SF_STR_ARTIST : name = "ARTIST" ; break ; case SF_STR_COMMENT : name = "COMMENT" ; break ; case SF_STR_DATE : name = "DATE" ; break ; case SF_STR_ALBUM : name = "ALBUM" ; break ; case SF_STR_LICENSE : name = "LICENSE" ; break ; default : continue ; } ; vorbis_comment_add_tag (&vdata->vcomment, name, psf->strings.data [k].str) ; } ; /* set up the analysis state and auxiliary encoding storage */ vorbis_analysis_init (&vdata->vdsp, &vdata->vinfo) ; vorbis_block_init (&vdata->vdsp, &vdata->vblock) ; /* ** Set up our packet->stream encoder. ** Pick a random serial number ; that way we can more likely build ** chained streams just by concatenation. */ ogg_stream_init (&odata->ostream, psf_rand_int32 ()) ; /* Vorbis streams begin with three headers ; the initial header (with most of the codec setup parameters) which is mandated by the Ogg bitstream spec. The second header holds any comment fields. The third header holds the bitstream codebook. We merely need to make the headers, then pass them to libvorbis one at a time ; libvorbis handles the additional Ogg bitstream constraints */ { ogg_packet header ; ogg_packet header_comm ; ogg_packet header_code ; int result ; vorbis_analysis_headerout (&vdata->vdsp, &vdata->vcomment, &header, &header_comm, &header_code) ; ogg_stream_packetin (&odata->ostream, &header) ; /* automatically placed in its own page */ ogg_stream_packetin (&odata->ostream, &header_comm) ; ogg_stream_packetin (&odata->ostream, &header_code) ; /* This ensures the actual * audio data will start on a new page, as per spec */ while ((result = ogg_stream_flush (&odata->ostream, &odata->opage)) != 0) { psf_fwrite (odata->opage.header, 1, odata->opage.header_len, psf) ; psf_fwrite (odata->opage.body, 1, odata->opage.body_len, psf) ; } ; } return 0 ; } /* vorbis_write_header */
//TODO: vorbis/theora-header&init in sub-functions //TODO: "clean" error-returns ... int Cin_OGM_Init(const char* filename) { int status; ogg_page og; ogg_packet op; int i; if(g_ogm.ogmFile) { Com_Printf("WARNING: it seams there was already a ogm running, it will be killed to start %s\n", filename); Cin_OGM_Shutdown(); } memset(&g_ogm,0,sizeof(cin_ogm_t)); FS_FOpenFileRead(filename, &g_ogm.ogmFile, qtrue); if(!g_ogm.ogmFile) { Com_Printf("Can't open ogm-file for reading (%s)\n", filename); return -1; } ogg_sync_init(&g_ogm.oy); /* Now we can read pages */ //FIXME? can serialno be 0 in ogg? (better way to check inited?) //TODO: support for more than one audio stream? / detect files with one stream(or without correct ones) while(!g_ogm.os_audio.serialno || !g_ogm.os_video.serialno) { if(ogg_sync_pageout(&g_ogm.oy,&og)==1) { if(strstr((char*)(og.body+1),"vorbis")) { //FIXME? better way to find audio stream if(g_ogm.os_audio.serialno) { Com_Printf("more than one audio stream, in ogm-file(%s) ... we will stay at the first one\n",filename); } else { ogg_stream_init(&g_ogm.os_audio, ogg_page_serialno(&og)); ogg_stream_pagein(&g_ogm.os_audio,&og); } } #ifdef USE_CIN_THEORA if(strstr((char*)(og.body+1),"theora")) { if(g_ogm.os_video.serialno) { Com_Printf("more than one video stream, in ogm-file(%s) ... we will stay at the first one\n",filename); } else{ g_ogm.videoStreamIsTheora = qtrue; ogg_stream_init(&g_ogm.os_video, ogg_page_serialno(&og)); ogg_stream_pagein(&g_ogm.os_video,&og); } } #endif #ifdef USE_CIN_XVID if(strstr((char*)(og.body+1),"video")) { //FIXME? better way to find video stream if(g_ogm.os_video.serialno) { Com_Printf("more than one video stream, in ogm-file(%s) ... we will stay at the first one\n",filename); } else{ stream_header_t* sh; g_ogm.videoStreamIsXvid = qtrue; sh = (stream_header_t*)(og.body+1); //TODO: one solution for checking xvid and theora if(!isPowerOf2(sh->sh.stream_header_video.width)) { Com_Printf("VideoWidth of the ogm-file isn't a power of 2 value (%s)\n", filename); return -5; } if(!isPowerOf2(sh->sh.stream_header_video.height)) { Com_Printf("VideoHeight of the ogm-file isn't a power of 2 value (%s)\n", filename); return -6; } g_ogm.Vtime_unit = sh->time_unit; ogg_stream_init(&g_ogm.os_video, ogg_page_serialno(&og)); ogg_stream_pagein(&g_ogm.os_video,&og); } } #endif } else if(loadBlockToSync()) break; } if(g_ogm.videoStreamIsXvid && g_ogm.videoStreamIsTheora) { Com_Printf("Found \"video\"- and \"theora\"-stream ,ogm-file (%s)\n", filename); return -2; } if(!g_ogm.os_audio.serialno) { Com_Printf("Haven't found a audio(vorbis) stream in ogm-file (%s)\n", filename); return -2; } if(!g_ogm.os_video.serialno) { Com_Printf("Haven't found a video stream in ogm-file (%s)\n", filename); return -3; } //load vorbis header vorbis_info_init(&g_ogm.vi); vorbis_comment_init(&g_ogm.vc); i=0; while(i<3) { status = ogg_stream_packetout(&g_ogm.os_audio,&op); if(status<0) { Com_Printf("Corrupt ogg packet while loading vorbis-headers, ogm-file(%s)\n", filename); return -8; } if(status>0) { status = vorbis_synthesis_headerin(&g_ogm.vi,&g_ogm.vc,&op); if(i==0 && status<0) { Com_Printf("This Ogg bitstream does not contain Vorbis audio data, ogm-file(%s)\n", filename); return -9; } ++i; } else if(loadPagesToStreams()) { if(loadBlockToSync()) { Com_Printf("Couldn't find all vorbis headers before end of ogm-file (%s)\n", filename); return -10; } } } vorbis_synthesis_init(&g_ogm.vd,&g_ogm.vi); #ifdef USE_CIN_XVID status = init_xvid(); if (status) { Com_Printf("[Xvid]Decore INIT problem, return value %d(ogm-file: %s)\n", status, filename); return -4; } #endif #ifdef USE_CIN_THEORA if(g_ogm.videoStreamIsTheora) { ROQ_GenYUVTables(); theora_info_init(&g_ogm.th_info); theora_comment_init(&g_ogm.th_comment); i=0; while(i<3) { status = ogg_stream_packetout(&g_ogm.os_video,&op); if(status<0) { Com_Printf("Corrupt ogg packet while loading theora-headers, ogm-file(%s)\n", filename); return -8; } if(status>0) { status = theora_decode_header(&g_ogm.th_info, &g_ogm.th_comment, &op); if(i==0 && status!=0) { Com_Printf("This Ogg bitstream does not contain theora data, ogm-file(%s)\n", filename); return -9; } ++i; } else if(loadPagesToStreams()) { if(loadBlockToSync()) { Com_Printf("Couldn't find all theora headers before end of ogm-file (%s)\n", filename); return -10; } } } theora_decode_init(&g_ogm.th_state, &g_ogm.th_info); if(!isPowerOf2(g_ogm.th_info.width)) { Com_Printf("VideoWidth of the ogm-file isn't a power of 2 value (%s)\n", filename); return -5; } if(!isPowerOf2(g_ogm.th_info.height)) { Com_Printf("VideoHeight of the ogm-file isn't a power of 2 value (%s)\n", filename); return -6; } g_ogm.Vtime_unit = ((ogg_int64_t)g_ogm.th_info.fps_denominator *1000*10000 / g_ogm.th_info.fps_numerator); } #endif Com_DPrintf("OGM-Init done (%s)\n",filename); return 0; }
void parseHeaders(){ /* extracted from player_sample.c test file for theora alpha */ ogg_packet op; /* Parse the headers */ /* Only interested in Vorbis/Theora streams */ while(!stateflag){ int ret=buffer_data(&oy); if(ret==0)break; while(ogg_sync_pageout(&oy,&og)>0){ ogg_stream_state test; /* is this a mandated initial header? If not, stop parsing */ if(!ogg_page_bos(&og)){ /* don't leak the page; get it into the appropriate stream */ queue_page(&og); stateflag=1; break; } ogg_stream_init(&test,ogg_page_serialno(&og)); ogg_stream_pagein(&test,&og); ogg_stream_packetout(&test,&op); /* identify the codec: try theora */ if(!theora_p && theora_decode_header(&ti,&tc,&op)>=0){ /* it is theora */ memcpy(&to,&test,sizeof(test)); theora_p=1; }else if(!vorbis_p && vorbis_synthesis_headerin(&vi,&vc,&op)>=0){ /* it is vorbis */ memcpy(&vo,&test,sizeof(test)); vorbis_p=1; }else{ /* whatever it is, we don't care about it */ ogg_stream_clear(&test); } } } /* we've now identified all the bitstreams. parse the secondary header packets. */ while((theora_p && theora_p<3) || (vorbis_p && vorbis_p<3)){ int ret; /* look for further theora headers */ while(theora_p && (theora_p<3) && (ret=ogg_stream_packetout(&to,&op))){ if(ret<0){ printf("Error parsing Theora stream headers; corrupt stream?\n"); exit(1); } if(theora_decode_header(&ti,&tc,&op)){ printf("Error parsing Theora stream headers; corrupt stream?\n"); exit(1); } theora_p++; if(theora_p==3)break; } /* look for more vorbis header packets */ while(vorbis_p && (vorbis_p<3) && (ret=ogg_stream_packetout(&vo,&op))){ if(ret<0){ printf("Error parsing Vorbis stream headers; corrupt stream?\n"); exit(1); } if(vorbis_synthesis_headerin(&vi,&vc,&op)){ printf("Error parsing Vorbis stream headers; corrupt stream?\n"); exit(1); } vorbis_p++; if(vorbis_p==3)break; } /* The header pages/packets will arrive before anything else we care about, or the stream is not obeying spec */ if(ogg_sync_pageout(&oy,&og)>0){ queue_page(&og); /* demux into the appropriate stream */ }else{ int ret=buffer_data(&oy); if(ret==0){ fprintf(stderr,"End of file while searching for codec headers.\n"); exit(1); } } } }
void rip_ogg_process_chunk(RIP_MANAGER_INFO * rmi, LIST * page_list, const char *buf, u_long size, TRACK_INFO * ti) { OGG_PAGE_LIST *ol; int header; int ret; char *buffer; // static ogg_int64_t written = 0; // static unsigned int written = 0; // static int ogg_page2 = 0; INIT_LIST_HEAD(page_list); debug_printf("-- rip_ogg_process_chunk (%d)\n", size); buffer = ogg_sync_buffer(&rmi->ogg_sync, size); memcpy(buffer, buf, size); ogg_sync_wrote(&rmi->ogg_sync, size); do { switch (ret = ogg_sync_pageout(&rmi->ogg_sync, &rmi->ogg_pg)) { case -1: /* -1 if we were not properly synced and had to skip some bytes */ debug_printf("Hole in ogg, skipping bytes\n"); break; case 0: /* 0 if we need more data to verify a page */ debug_printf("Ogg needs more data\n"); break; case 1: /* 1 if we have a page */ debug_printf("Found an ogg page!\n"); /* Do stuff needed for decoding vorbis */ if (ogg_page_bos(&rmi->ogg_pg)) { int rc; ogg_packet packet; ogg_stream_init(&rmi->stream.os, ogg_page_serialno(&rmi->ogg_pg)); ogg_stream_pagein(&rmi->stream.os, &rmi->ogg_pg); rc = ogg_stream_packetout(&rmi->stream.os, &packet); if (rc <= 0) { printf("Warning: Invalid header page, no packet found\n"); // null_start (&rmi->stream); exit(1); } else if (packet.bytes >= 7 && memcmp(packet.packet, "\001vorbis", 7) == 0) { vorbis_start(&rmi->stream); } } header = vorbis_process(rmi, &rmi->stream, &rmi->ogg_pg, ti); if (ogg_page_eos(&rmi->ogg_pg)) { vorbis_end(&rmi->stream); } /* Create ogg page boundary struct */ ol = (OGG_PAGE_LIST *) malloc(sizeof(OGG_PAGE_LIST)); if (!ol) { printf("Malloc error\n"); exit(1); } ol->m_page_len = rmi->ogg_pg.header_len + rmi->ogg_pg.body_len; ol->m_page_flags = 0; /* ***************************************************** Create header buffer for relay stream. A pointer to the header buffer will attached to all pages after page 2. If a relay connects in the middle of a song, we send the header to the relay. Finally, the memory for the header is freed when the last page of the song is ejected from the cbuf. ** ***************************************************** */ if (ogg_page_bos(&rmi->ogg_pg)) { /* First page in song */ ol->m_page_flags |= OGG_PAGE_BOS; ol->m_header_buf_ptr = 0; ol->m_header_buf_len = 0; rmi->ogg_curr_header = (char *)malloc(ol->m_page_len); rmi->ogg_curr_header_len = ol->m_page_len; memcpy(rmi->ogg_curr_header, rmi->ogg_pg.header, rmi->ogg_pg.header_len); memcpy(rmi->ogg_curr_header + rmi->ogg_pg.header_len, rmi->ogg_pg.body, rmi->ogg_pg.body_len); } else if (header) { /* Second or third page in song */ ol->m_page_flags |= OGG_PAGE_2; ol->m_header_buf_ptr = 0; ol->m_header_buf_len = 0; rmi->ogg_curr_header = (char *) realloc(rmi->ogg_curr_header, rmi->ogg_curr_header_len + ol->m_page_len); memcpy(rmi->ogg_curr_header + rmi->ogg_curr_header_len, rmi->ogg_pg.header, rmi->ogg_pg.header_len); memcpy(rmi->ogg_curr_header + rmi->ogg_curr_header_len + rmi->ogg_pg.header_len, rmi->ogg_pg.body, rmi->ogg_pg.body_len); rmi->ogg_curr_header_len += ol->m_page_len; } else if (!ogg_page_eos(&rmi->ogg_pg)) { /* Middle pages in song */ ol->m_header_buf_ptr = rmi->ogg_curr_header; ol->m_header_buf_len = rmi->ogg_curr_header_len; } else { /* Last page in song */ ol->m_page_flags |= OGG_PAGE_EOS; ol->m_header_buf_ptr = rmi->ogg_curr_header; ol->m_header_buf_len = rmi->ogg_curr_header_len; rmi->ogg_curr_header = 0; rmi->ogg_curr_header_len = 0; } debug_printf("OGG_PAGE\n" " header_len = %d\n" " body_len = %d\n" " serial no = %d\n" " page no = %d\n" " bos? = %d\n" " eos? = %d\n", rmi->ogg_pg.header_len, rmi->ogg_pg.body_len, ogg_page_serialno(&rmi->ogg_pg), ogg_page_pageno(&rmi->ogg_pg), ogg_page_bos(&rmi->ogg_pg), ogg_page_eos(&rmi->ogg_pg)); list_add_tail(&(ol->m_list), page_list); break; } } while (ret != 0); debug_printf("OGG_SYNC state:\n" " storage = %d\n" " fill = %d\n" " returned = %d\n" " unsynced = %d\n" " headerbytes = %d\n" " bodybytes = %d\n", rmi->ogg_sync.storage, rmi->ogg_sync.fill, rmi->ogg_sync.returned, rmi->ogg_sync.unsynced, rmi->ogg_sync.headerbytes, rmi->ogg_sync.bodybytes); // return 1; }
int initRecorder(const char *path) { cleanupRecorder(); if (!path) { return 0; } _fileOs = fopen(path, "wb"); if (!_fileOs) { return 0; } inopt.rate = rate; inopt.gain = 0; inopt.endianness = 0; inopt.copy_comments = 0; inopt.rawmode = 1; inopt.ignorelength = 1; inopt.samplesize = 16; inopt.channels = 1; inopt.skip = 0; comment_init(&inopt.comments, &inopt.comments_length, opus_get_version_string()); if (rate > 24000) { coding_rate = 48000; } else if (rate > 16000) { coding_rate = 24000; } else if (rate > 12000) { coding_rate = 16000; } else if (rate > 8000) { coding_rate = 12000; } else { coding_rate = 8000; } if (rate != coding_rate) { LOGE("Invalid rate"); return 0; } header.channels = 1; header.channel_mapping = 0; header.input_sample_rate = rate; header.gain = inopt.gain; header.nb_streams = 1; int result = OPUS_OK; _encoder = opus_encoder_create(coding_rate, 1, OPUS_APPLICATION_AUDIO, &result); if (result != OPUS_OK) { LOGE("Error cannot create encoder: %s", opus_strerror(result)); return 0; } min_bytes = max_frame_bytes = (1275 * 3 + 7) * header.nb_streams; _packet = malloc(max_frame_bytes); result = opus_encoder_ctl(_encoder, OPUS_SET_BITRATE(bitrate)); if (result != OPUS_OK) { LOGE("Error OPUS_SET_BITRATE returned: %s", opus_strerror(result)); return 0; } #ifdef OPUS_SET_LSB_DEPTH result = opus_encoder_ctl(_encoder, OPUS_SET_LSB_DEPTH(max(8, min(24, inopt.samplesize)))); if (result != OPUS_OK) { LOGE("Warning OPUS_SET_LSB_DEPTH returned: %s", opus_strerror(result)); } #endif opus_int32 lookahead; result = opus_encoder_ctl(_encoder, OPUS_GET_LOOKAHEAD(&lookahead)); if (result != OPUS_OK) { LOGE("Error OPUS_GET_LOOKAHEAD returned: %s", opus_strerror(result)); return 0; } inopt.skip += lookahead; header.preskip = (int)(inopt.skip * (48000.0 / coding_rate)); inopt.extraout = (int)(header.preskip * (rate / 48000.0)); if (ogg_stream_init(&os, rand()) == -1) { LOGE("Error: stream init failed"); return 0; } unsigned char header_data[100]; int packet_size = opus_header_to_packet(&header, header_data, 100); op.packet = header_data; op.bytes = packet_size; op.b_o_s = 1; op.e_o_s = 0; op.granulepos = 0; op.packetno = 0; ogg_stream_packetin(&os, &op); while ((result = ogg_stream_flush(&os, &og))) { if (!result) { break; } int pageBytesWritten = writeOggPage(&og, _fileOs); if (pageBytesWritten != og.header_len + og.body_len) { LOGE("Error: failed writing header to output stream"); return 0; } bytes_written += pageBytesWritten; pages_out++; } comment_pad(&inopt.comments, &inopt.comments_length, comment_padding); op.packet = (unsigned char *)inopt.comments; op.bytes = inopt.comments_length; op.b_o_s = 0; op.e_o_s = 0; op.granulepos = 0; op.packetno = 1; ogg_stream_packetin(&os, &op); while ((result = ogg_stream_flush(&os, &og))) { if (result == 0) { break; } int writtenPageBytes = writeOggPage(&og, _fileOs); if (writtenPageBytes != og.header_len + og.body_len) { LOGE("Error: failed writing header to output stream"); return 0; } bytes_written += writtenPageBytes; pages_out++; } free(inopt.comments); return 1; }
/* The following function is basically a hacked version of the code in * examples/encoder_example.c */ void write_vorbis_data_or_die (const char *filename, int srate, float q, const float * data, int count, int ch) { FILE * file ; ogg_stream_state os; ogg_page og; ogg_packet op; vorbis_info vi; vorbis_comment vc; vorbis_dsp_state vd; vorbis_block vb; int eos = 0, ret; if ((file = fopen (filename, "wb")) == NULL) { printf("\n\nError : fopen failed : %s\n", strerror (errno)) ; exit (1) ; } /********** Encode setup ************/ vorbis_info_init (&vi); ret = vorbis_encode_init_vbr (&vi,ch,srate,q); if (ret) { printf ("vorbis_encode_init_vbr return %d\n", ret) ; exit (1) ; } vorbis_comment_init (&vc); vorbis_comment_add_tag (&vc,"ENCODER","test/util.c"); vorbis_analysis_init (&vd,&vi); vorbis_block_init (&vd,&vb); ogg_stream_init (&os,12345678); { ogg_packet header; ogg_packet header_comm; ogg_packet header_code; vorbis_analysis_headerout (&vd,&vc,&header,&header_comm,&header_code); ogg_stream_packetin (&os,&header); ogg_stream_packetin (&os,&header_comm); ogg_stream_packetin (&os,&header_code); /* Ensures the audio data will start on a new page. */ while (!eos){ int result = ogg_stream_flush (&os,&og); if (result == 0) break; fwrite (og.header,1,og.header_len,file); fwrite (og.body,1,og.body_len,file); } } { /* expose the buffer to submit data */ float **buffer = vorbis_analysis_buffer (&vd,count); int i; for(i=0;i<ch;i++) memcpy (buffer [i], data, count * sizeof (float)) ; /* tell the library how much we actually submitted */ vorbis_analysis_wrote (&vd,count); vorbis_analysis_wrote (&vd,0); } while (vorbis_analysis_blockout (&vd,&vb) == 1) { vorbis_analysis (&vb,NULL); vorbis_bitrate_addblock (&vb); while (vorbis_bitrate_flushpacket (&vd,&op)) { ogg_stream_packetin (&os,&op); while (!eos) { int result = ogg_stream_pageout (&os,&og); if (result == 0) break; fwrite (og.header,1,og.header_len,file); fwrite (og.body,1,og.body_len,file); if (ogg_page_eos (&og)) eos = 1; } } } ogg_stream_clear (&os); vorbis_block_clear (&vb); vorbis_dsp_clear (&vd); vorbis_comment_clear (&vc); vorbis_info_clear (&vi); fclose (file) ; }
int OggDec::DecodeOGG(char *inmemory,int inmemsize, char *outmemory,int outmemsize,int *done) { char *buffer; int i; *done = 0; if(leakSize){ if(outmemsize >= leakSize){ memcpy(outmemory,leak_mem,leakSize); *done = leakSize; free(leak_mem); leak_mem = NULL; leakSize = 0; allocMemSize = 0; }else{ memcpy(outmemory,leak_mem,outmemsize); *done = outmemsize; memmove(leak_mem,leak_mem+outmemsize,leakSize-outmemsize); leakSize -= outmemsize; } if(inmemsize==0) return (OGG_DEC_CONTINUE); } if(0==decStep){ eos = 0; buffer=ogg_sync_buffer(&oy,4096); memcpy(buffer,inmemory,inmemsize); ogg_sync_wrote(&oy,inmemsize); if(ogg_sync_pageout(&oy,&og)!=1){ if(inmemsize<4096){ Clear_ogg(); return(OGG_DEC_END); } return(OGG_DEC_ERR); } ogg_stream_init(&os,ogg_page_serialno(&og)); vorbis_info_init(&vi); vorbis_comment_init(&vc); if(ogg_stream_pagein(&os,&og)<0){ return(OGG_DEC_ERR); } if(ogg_stream_packetout(&os,&op)!=1){ return(OGG_DEC_ERR); } if(vorbis_synthesis_headerin(&vi,&vc,&op)<0){ return(OGG_DEC_ERR); } wfmt.wFormatTag = WAVE_FORMAT_PCM; wfmt.nChannels = vi.channels; wfmt.wBitsPerSample = 16; wfmt.nSamplesPerSec = vi.rate; wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample/8); wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign; wfmt.cbSize = 0; bWaveGet = TRUE; decStep = 1; d1loop=0; return (OGG_DEC_CONTINUE); } if(1==decStep){ while(d1loop<2){ while(d1loop<2){ int result=ogg_sync_pageout(&oy,&og); if(result==0)break; if(result==1){ ogg_stream_pagein(&os,&og); while(d1loop<2){ result=ogg_stream_packetout(&os,&op); if(result==0)break; if(result<0){ return(OGG_DEC_ERR); } vorbis_synthesis_headerin(&vi,&vc,&op); d1loop++; } } } buffer=ogg_sync_buffer(&oy,4096); memcpy(buffer,inmemory,inmemsize); if(inmemsize==0 && d1loop<2){ return(OGG_DEC_ERR); } ogg_sync_wrote(&oy,inmemsize); if(d1loop<2) return (OGG_DEC_CONTINUE); } decStep = 2; convsize=4096/vi.channels; vorbis_synthesis_init(&vd,&vi); vorbis_block_init(&vd,&vb); return (OGG_DEC_CONTINUE); } while(!eos){ while(!eos){ int result=ogg_sync_pageout(&oy,&og); if(result==0)break; if(result<0){ }else{ ogg_stream_pagein(&os,&og); while(1){ result=ogg_stream_packetout(&os,&op); if(result==0)break; if(result<0){ }else{ float **pcm; int samples; if(vorbis_synthesis(&vb,&op)==0) vorbis_synthesis_blockin(&vd,&vb); while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0){ int j; int clipflag=0; int bout=(samples<convsize?samples:convsize); for(i=0;i<vi.channels;i++){ ogg_int16_t *ptr=convbuffer+i; float *mono=pcm[i]; for(j=0;j<bout;j++){ #if 1 int val=int(mono[j]*32767.f); #else int val=mono[j]*32767.f+drand48()-0.5f; #endif if(val>32767){ val=32767; clipflag=1; } if(val<-32768){ val=-32768; clipflag=1; } *ptr=val; ptr+=(vi.channels); } } if(NULL==leak_mem){ if(outmemsize >= (*done +2*vi.channels*bout)){ memcpy(outmemory+(*done),convbuffer,2*vi.channels*bout); *done += 2*vi.channels*bout; }else{ allocMemSize = 0x100000; leak_mem = (char *)malloc(allocMemSize); } } if(leak_mem){ if(allocMemSize < (leakSize + 2*vi.channels*bout)){ allocMemSize += 0x100000; realloc(leak_mem,allocMemSize); } memcpy(leak_mem+leakSize,convbuffer,2*vi.channels*bout); leakSize += 2*vi.channels*bout; } vorbis_synthesis_read(&vd,bout); } } } if(ogg_page_eos(&og))eos=1; } } if(!eos){ buffer=ogg_sync_buffer(&oy,4096); memcpy(buffer,inmemory,inmemsize); ogg_sync_wrote(&oy,inmemsize); if(inmemsize==0) eos=1; return (OGG_DEC_CONTINUE); } } if(bLoop){ eos = 0; return OGG_DEC_REPLAY; } ogg_stream_clear(&os); vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); decStep = 0; return (OGG_DEC_CONTINUE); }
ogg_ostream::ogg_ostream(int serial_number, std::ostream & output) : output_(output) { CHECK(ogg_stream_init(&stream_state_, serial_number) == 0); }
void AudioStreamPlaybackSpeex::reload() { if (active) unload(); if (!data.size()) return; ogg_sync_init(&oy); speex_bits_init(&bits); read_ofs = 0; // char *buf; int packet_count = 0; int extra_headers = 0; int stream_init = 0; page_granule=0; last_granule=0; skip_samples=0; page_nb_packets=0; packets_available=false; packet_no=0; int eos = 0; do { /*Get the ogg buffer for writing*/ int nb_read = MIN(data.size() - read_ofs, READ_CHUNK); char* ogg_dst = ogg_sync_buffer(&oy, nb_read); /*Read bitstream from input file*/ copymem(ogg_dst, &data[read_ofs], nb_read); read_ofs += nb_read; ogg_sync_wrote(&oy, nb_read); /*Loop for all complete pages we got (most likely only one)*/ while (ogg_sync_pageout(&oy, &og)==1) { int packet_no; if (stream_init == 0) { ogg_stream_init(&os, ogg_page_serialno(&og)); stream_init = 1; } /*Add page to the bitstream*/ ogg_stream_pagein(&os, &og); page_granule = ogg_page_granulepos(&og); page_nb_packets = ogg_page_packets(&og); if (page_granule>0 && frame_size) { skip_samples = page_nb_packets*frame_size*nframes - (page_granule-last_granule); if (ogg_page_eos(&og)) skip_samples = -skip_samples; /*else if (!ogg_page_bos(&og)) skip_samples = 0;*/ } else { skip_samples = 0; } last_granule = page_granule; /*Extract all available packets*/ packet_no=0; while (!eos && ogg_stream_packetout(&os, &op)==1) { /*If first packet, process as Speex header*/ if (packet_count==0) { int rate = 0; int channels; st = process_header(&op, &frame_size, &rate, &nframes, &channels, &extra_headers); if (!nframes) nframes=1; if (!st) { unload(); return; }; page_size = nframes * frame_size; stream_srate=rate; stream_channels=channels; stream_minbuff_size=page_size; } else if (packet_count==1) { } else if (packet_count<=1+extra_headers) { /* Ignore extra headers */ }; }; ++packet_count; }; } while (packet_count <= extra_headers); active=true; }
static int ogg_output_open(const char *fname, const char *comment) { int fd; static vorbis_info ogg_info; vorbis_info *vi; /* struct that stores all the static vorbis bitstream settings */ vorbis_comment vc; /* struct that stores all the user comments */ if(strcmp(fname, "-") == 0) { fd = 1; /* data to stdout */ if(comment == NULL) comment = "(stdout)"; } else { /* Open the audio file */ fd = open(fname, FILE_OUTPUT_MODE); if(fd < 0) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", fname, strerror(errno)); return -1; } if(comment == NULL) comment = fname; } /* choose an encoding mode */ /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */ memcpy(&ogg_info, &info_A, sizeof(ogg_info)); if(dpm.encoding & PE_MONO) ogg_info.channels = 1; else ogg_info.channels = 2; ogg_info.rate = dpm.rate; vi = &ogg_info; /* add a comment */ vorbis_comment_init(&vc); vorbis_comment_add(&vc, (char *)comment); /* set up the analysis state and auxiliary encoding storage */ vorbis_analysis_init(&vd, vi); vorbis_block_init(&vd, &vb); /* set up our packet->stream encoder */ /* pick a random serial number; that way we can more likely build chained streams just by concatenation */ srand(time(NULL)); ogg_stream_init(&os, rand()); /* Vorbis streams begin with three headers; the initial header (with most of the codec setup parameters) which is mandated by the Ogg bitstream spec. The second header holds any comment fields. The third header holds the bitstream codebook. We merely need to make the headers, then pass them to libvorbis one at a time; libvorbis handles the additional Ogg bitstream constraints */ { ogg_packet header; ogg_packet header_comm; ogg_packet header_code; vorbis_analysis_headerout(&vd, &vc, &header, &header_comm, &header_code); ogg_stream_packetin(&os, &header); /* automatically placed in its own page */ ogg_stream_packetin(&os, &header_comm); ogg_stream_packetin(&os, &header_code); /* no need to write out here. We'll get to that in the main loop */ } return fd; }