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]; celt_int32 frame_size = 960; int quiet=0; int nbBytes; CELTMode *mode; void *st; unsigned char bits[MAX_FRAME_BYTES]; int with_cbr = 0; int with_cvbr = 0; int with_skeleton = 0; int total_bytes = 0; int peak_bytes = 0; struct option long_options[] = { {"bitrate", required_argument, NULL, 0}, {"cbr",no_argument,NULL, 0}, {"cvbr",no_argument,NULL, 0}, {"comp", required_argument, NULL, 0}, {"nopf", no_argument, NULL, 0}, {"independent", no_argument, NULL, 0}, {"framesize", required_argument, NULL, 0}, {"skeleton",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}, {"mono", 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; celt_int32 rate=48000; celt_int32 size; int chan=1; int fmt=16; int lsb=1; ogg_stream_state os; ogg_stream_state so; /* ogg stream for skeleton bitstream */ ogg_page og; ogg_packet op; int bytes_written=0, ret, result; int id=-1; CELTHeader header; char vendor_string[64]; char *comments; int comments_length; int close_in=0, close_out=0; int eos=0; float bitrate=-1; char first_bytes[12]; int wave_input=0; celt_int32 lookahead = 0; int bytes_per_packet=-1; int complexity=-127; int prediction=2; /*Process command-line options*/ while(1) { c = getopt_long (argc, argv, "hvV", long_options, &option_index); if (c==-1) break; switch(c) { case 0: if (strcmp(long_options[option_index].name,"bitrate")==0) { bitrate = atof (optarg); } else if (strcmp(long_options[option_index].name,"cbr")==0) { with_cbr=1; } else if (strcmp(long_options[option_index].name,"cvbr")==0) { with_cvbr=1; } else if (strcmp(long_options[option_index].name,"skeleton")==0) { with_skeleton=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,"mono")==0) { chan=1; } else if (strcmp(long_options[option_index].name,"rate")==0) { rate=atoi (optarg); } else if (strcmp(long_options[option_index].name,"comp")==0) { complexity=atoi (optarg); } else if (strcmp(long_options[option_index].name,"framesize")==0) { frame_size=atoi (optarg); } else if (strcmp(long_options[option_index].name,"nopf")==0) { if (prediction>1) prediction=1; } else if (strcmp(long_options[option_index].name,"independent")==0) { prediction=0; } 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 'h': usage(); exit(0); break; case 'v': version(); exit(0); break; case 'V': print_bitrate=1; 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 (with_skeleton && ogg_stream_init(&so, 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); #elif defined OS2 _fsetmode(stdin,"b"); #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 (bitrate<=0.005) if (chan==1) bitrate=64.0; else bitrate=128.0; bytes_per_packet = MAX_FRAME_BYTES; mode = celt_mode_create(rate, frame_size, NULL); if (!mode) return 1; snprintf(vendor_string, sizeof(vendor_string), "Encoded with CELT %s\n",CELT_VERSION); comment_init(&comments, &comments_length, vendor_string); /*celt_mode_info(mode, CELT_GET_FRAME_SIZE, &frame_size);*/ celt_header_init(&header, mode, frame_size, chan); header.nb_channels = chan; { char *st_string="mono"; if (chan==2) st_string="stereo"; if (!quiet) if (with_cbr) fprintf (stderr, "Encoding %.0f kHz %s audio in %.0fms packets at %0.3fkbit/sec (%d bytes per packet, CBR)\n", header.sample_rate/1000., st_string, frame_size/(float)header.sample_rate*1000., bitrate, bytes_per_packet); else fprintf (stderr, "Encoding %.0f kHz %s audio in %.0fms packets at %0.3fkbit/sec (%d bytes per packet maximum)\n", header.sample_rate/1000., st_string, frame_size/(float)header.sample_rate*1000., bitrate, bytes_per_packet); } /*Initialize CELT encoder*/ st = celt_encoder_create_custom(mode, chan, NULL); { int tmp = (bitrate*1000); if (celt_encoder_ctl(st, CELT_SET_BITRATE(tmp)) != CELT_OK) { fprintf (stderr, "bitrate request failed\n"); return 1; } } if (!with_cbr) { if (celt_encoder_ctl(st, CELT_SET_VBR(1)) != CELT_OK) { fprintf (stderr, "VBR request failed\n"); return 1; } if (!with_cvbr) { if (celt_encoder_ctl(st, CELT_SET_VBR_CONSTRAINT(0)) != CELT_OK) { fprintf (stderr, "VBR constraint failed\n"); return 1; } } } if (celt_encoder_ctl(st, CELT_SET_PREDICTION(prediction)) != CELT_OK) { fprintf (stderr, "Prediction request failed\n"); return 1; } if (complexity!=-127) { if (celt_encoder_ctl(st, CELT_SET_COMPLEXITY(complexity)) != CELT_OK) { fprintf (stderr, "Only complexity 0 through 10 is supported\n"); return 1; } } 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; } if (with_skeleton) { fprintf (stderr, "Warning: Enabling skeleton output may cause some decoders to fail.\n"); } /* first packet should be the skeleton header. */ if (with_skeleton) { add_fishead_packet(&so); if ((ret = flush_ogg_stream_to_file(&so, fout))) { fprintf (stderr,"Error: failed skeleton (fishead) header to output stream\n"); exit(1); } else bytes_written += ret; } /*Write header*/ { unsigned char header_data[100]; int packet_size = celt_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; 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; } 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); } /* fisbone packet should be write after all bos pages */ if (with_skeleton) { add_fisbone_packet(&so, os.serialno, &header); if ((ret = flush_ogg_stream_to_file(&so, fout))) { fprintf (stderr,"Error: failed writing skeleton (fisbone )header to output stream\n"); exit(1); } else bytes_written += ret; } /* writing the rest of the celt header packets */ 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); /* write the skeleton eos packet */ if (with_skeleton) { add_eos_packet_to_stream(&so); if ((ret = flush_ogg_stream_to_file(&so, fout))) { fprintf (stderr,"Error: failed writing skeleton header to output stream\n"); exit(1); } else bytes_written += ret; } 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*/ nbBytes = celt_encode(st, input, frame_size, bits, bytes_per_packet); if (nbBytes<0) { fprintf(stderr, "Got error %d while encoding. Aborting.\n", nbBytes); break; } nb_encoded += frame_size; total_bytes += nbBytes; peak_bytes=IMAX(nbBytes,peak_bytes); 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; op.packet = (unsigned char *)bits; 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; 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; } } /*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; } if (!with_cbr && !quiet) fprintf (stderr, "Average rate %0.3fkbit/sec, %d peak bytes per packet\n", (total_bytes*8.0/((float)nb_encoded/header.sample_rate))/1000.0, peak_bytes); celt_encoder_destroy(st); celt_mode_destroy(mode); ogg_stream_clear(&os); if (close_in) fclose(fin); if (close_out) fclose(fout); return 0; }
static GstFlowReturn gst_celt_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf) { GstCeltEnc *enc; GstFlowReturn ret = GST_FLOW_OK; enc = GST_CELT_ENC (benc); if (!enc->header_sent) { /* Celt streams begin with two 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. We merely need to make the headers, then pass them to libcelt one at a time; libcelt handles the additional Ogg bitstream constraints */ GstBuffer *buf1, *buf2; GstCaps *caps; /* libcelt has a bug which underestimates header size by 4... */ unsigned int header_size = enc->header.header_size + 4; unsigned char *data = g_malloc (header_size); /* create header buffer */ int error = celt_header_to_packet (&enc->header, data, header_size); if (error < 0) { g_free (data); goto no_header; } buf1 = gst_buffer_new (); GST_BUFFER_DATA (buf1) = GST_BUFFER_MALLOCDATA (buf1) = data; GST_BUFFER_SIZE (buf1) = header_size; GST_BUFFER_OFFSET_END (buf1) = 0; GST_BUFFER_OFFSET (buf1) = 0; /* create comment buffer */ buf2 = gst_celt_enc_create_metadata_buffer (enc); /* mark and put on caps */ caps = gst_pad_get_caps (GST_AUDIO_ENCODER_SRC_PAD (enc)); gst_caps_set_simple (caps, "rate", G_TYPE_INT, enc->rate, "channels", G_TYPE_INT, enc->channels, "frame-size", G_TYPE_INT, enc->frame_size, NULL); caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL); /* negotiate with these caps */ GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps); GST_LOG_OBJECT (enc, "rate=%d channels=%d frame-size=%d", enc->rate, enc->channels, enc->frame_size); gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps); gst_buffer_set_caps (buf1, caps); gst_buffer_set_caps (buf2, caps); gst_caps_unref (caps); /* push out buffers */ /* store buffers for later pre_push sending */ g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL); enc->headers = NULL; GST_DEBUG_OBJECT (enc, "storing header buffers"); enc->headers = g_slist_prepend (enc->headers, buf2); enc->headers = g_slist_prepend (enc->headers, buf1); enc->header_sent = TRUE; } GST_DEBUG_OBJECT (enc, "received buffer %p of %u bytes", buf, buf ? GST_BUFFER_SIZE (buf) : 0); ret = gst_celt_enc_encode (enc, buf); done: return ret; /* ERRORS */ no_header: { GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), ("Failed to encode header")); ret = GST_FLOW_ERROR; goto done; } }