static long write_metadata_block_packets(FILE *out, const int serial, const char *vendor, const size_t num_tags, char **tags, size_t padding, ogg_packet **metadata) { const size_t header_length = vc_size(vendor, num_tags, tags); if (header_length > (2<<24)) return OGGEDIT_ALLOCATION_FAILURE; char magic[4]; magic[0] = VCTYPE; magic[1] = header_length >> 16 & 0xFF; magic[2] = header_length >> 8 & 0xFF; magic[3] = header_length & 0xFF; ogg_packet_clear(metadata[0]); if (!fill_vc_packet(magic, 4, vendor, num_tags, tags, false, padding, metadata[0])) return OGGEDIT_ALLOCATION_FAILURE; ogg_stream_state os; if (ogg_stream_init(&os, serial)) return OGGEDIT_FAILED_TO_INIT_STREAM; os.b_o_s = 1; os.pageno = 1; for (int i = 0; metadata[i]; i++) { if (!metadata[i+1]) metadata[i]->packet[0] |= LASTBLOCK; ogg_stream_packetin(&os, metadata[i]); } return flush_stream(out, &os); }
static PyObject * py_ogg_ogg_packet_clear(PyObject *self, PyObject *args) { int size; ogg_packet * op; PyArg_ParseTuple(args, "s#", &op, &size); ogg_packet_clear(op); Py_INCREF(Py_None); return Py_None; };
static void vcedit_clear_internals (vcedit_state *s) { ogg_stream_clear (&s->os); ogg_sync_clear (&s->oy); vorbis_info_clear (&s->vi); vorbis_comment_clear (&s->vc); free (s->vendor); s->vendor = NULL; ogg_packet_clear (&s->packet_main); ogg_packet_clear (&s->packet_code_books); s->serial = 0; s->opened = false; }
static void clear_header_list(ogg_packet **headers) { if (headers) { for (ogg_packet **header = headers; *header; header++) { ogg_packet_clear(*header); free(*header); } free(headers); } }
static int64_t write_opus_tags(FILE *out, const int64_t serial, const char *vendor, const uint32_t num_tags, char **tags, const size_t padding) { ogg_packet op; if (!fill_vc_packet(TAGMAGIC, strlen(TAGMAGIC), vendor, num_tags, tags, false, padding, &op)) return OGGEDIT_ALLOCATION_FAILURE; ogg_stream_state os; if (ogg_stream_init(&os, (int)serial)) return OGGEDIT_FAILED_TO_INIT_STREAM; os.b_o_s = 1; os.pageno = 1; ogg_stream_packetin(&os, &op); ogg_packet_clear(&op); return flush_stream(out, &os); }
/* This handles the headers at the backend, here we insert the header packets * we want for the queue. */ static int process_vorbis_headers (ogg_state_t *ogg_info, ogg_codec_t *codec) { vorbis_codec_t *source_vorbis = codec->specific; if (source_vorbis->header [0] == NULL) return 0; DEBUG0 ("Adding the 3 header packets"); ogg_stream_packetin (&source_vorbis->new_os, source_vorbis->header [0]); /* NOTE: we could build a separate comment packet each time */ if (source_vorbis->rebuild_comment) { vorbis_comment vc; ogg_packet header; ice_config_t *config; vorbis_comment_init (&vc); if (ogg_info->artist) vorbis_comment_add_tag (&vc, "artist", ogg_info->artist); if (ogg_info->title) vorbis_comment_add_tag (&vc, "title", ogg_info->title); config = config_get_config(); vorbis_comment_add_tag (&vc, "server", config->server_id); config_release_config(); vorbis_commentheader_out (&vc, &header); ogg_stream_packetin (&source_vorbis->new_os, &header); vorbis_comment_clear (&vc); ogg_packet_clear (&header); } else ogg_stream_packetin (&source_vorbis->new_os, source_vorbis->header [1]); ogg_stream_packetin (&source_vorbis->new_os, source_vorbis->header [2]); source_vorbis->rebuild_comment = 0; ogg_info->log_metadata = 1; source_vorbis->get_buffer_page = get_buffer_header; source_vorbis->process_packet = process_vorbis_audio; source_vorbis->granulepos = source_vorbis->prev_window; source_vorbis->initial_audio_packet = 1; return 1; }
void writeTheora(std::vector<std::vector<uint8_t>> vidframes, std::string writeTo, uint16_t vidWidth, uint16_t vidHeight) { // get paddings to nearest multiple of 0x10 uint32_t padW = 16 - vidWidth % 16; uint32_t padH = 16 - vidHeight % 16; uint32_t frmWidth = vidWidth + padW; uint32_t frmHeight = vidHeight + padH; // initialize theora stream th_info vidinfo; th_info_init(&vidinfo); vidinfo.frame_width = frmWidth; vidinfo.frame_height = frmHeight; vidinfo.pic_width = vidWidth; vidinfo.pic_height = vidHeight; vidinfo.pic_x = 0; vidinfo.pic_y = 0; vidinfo.colorspace = TH_CS_ITU_REC_470M; // what our RGB->YCbCr function operates on vidinfo.pixel_fmt = TH_PF_444; // we want the bestest video possible, so no decimation vidinfo.target_bitrate = 0; // prefer VBR with quality level... vidinfo.quality = 63; // ...which we want as high as possible (since we aren't using photographic frames, lossy compression ruins things) vidinfo.fps_numerator = 15; // framerate is 15 fps vidinfo.fps_denominator = 1; // initialize theora encoding context th_enc_ctx * videnc = th_encode_alloc(&vidinfo); // initialize theora comment th_comment vidcomment; th_comment_init(&vidcomment); // initialize ogg container ogg_stream_state vidcont; // serial number chosen by fair dice roll if (ogg_stream_init(&vidcont, 42)) { // returned -1, thus failed std::cerr << "Failed to initialize ogg container :(\n"; throw 42; } // get generic ogg packet & page holders ogg_packet vidpacket; ogg_page vidpage; // generic YCbCr frame, and initial data const int Y = 0; const int Cb = 1; const int Cr = 2; // clarity bonuses th_ycbcr_buffer rawdata; for (auto & i : rawdata) { i.width = i.stride = frmWidth; i.height = frmHeight; i.data = new unsigned char [frmWidth * frmHeight]; } // open file for writing std::ofstream vidfile; // because god forbid this thing supports an unsigned char unit vidfile.open(writeTo, std::ios::binary); // factor out the ogg page writing process a bit auto writePage = [&](){ vidfile.write((char*)vidpage.header, vidpage.header_len); if (!vidfile) { std::cerr << "An error occured in writing Ogg page header to file. Exiting...\n"; vidfile.close(); throw 42; } vidfile.write((char*)vidpage.body, vidpage.body_len); if (!vidfile) { std::cerr << "An error occured in writing Ogg page body to file. Exiting...\n"; vidfile.close(); throw 42; } }; // send header packets to ogg stream bool gotone = false; while (true) { int mkpacket = th_encode_flushheader(videnc, &vidcomment, &vidpacket); if (mkpacket == 0) { if (gotone) { break; } else { std::cerr << "Theora didn't return any header packets.\n"; throw 42; } } if (mkpacket < 0) { std::cerr << "Theora header flushing failed with error code " << mkpacket << ". Exiting...\n"; throw 42; } if (ogg_stream_packetin(&vidcont, &vidpacket)) { std::cerr << "Giving packet to Ogg failed, sorry.\n"; throw 42; } gotone = true; } // write ogg pages (and then the remainder via flush) to file while (ogg_stream_pageout(&vidcont, &vidpage)) { writePage(); } while (ogg_stream_flush(&vidcont, &vidpage)) { writePage(); } ////////////////////// // WRITE THE FRAMES // ////////////////////// for (int FRNO = 0; FRNO < vidframes.size(); FRNO++) { auto * VFR = &vidframes.at(FRNO); // since we set an offset of (0,0) for the picture, we fill up the // top and right edges of the frame with junk. This is us filling // the top part for (int i = 0; i < padH; i++) { for (int j = 0; j < frmWidth; j++) { rawdata[Y].data[i * frmWidth + j] = 0; rawdata[Cb].data[i * frmWidth + j] = 0; rawdata[Cr].data[i * frmWidth + j] = 0; } } // now for the picture itself (every row we add more junk to the right // of the image) int vecAt = 0; // where we are in the VFR vector for (int i = 0; i < vidHeight; i++) { for (int j = 0; j < vidWidth; j++) { rawdata[Y].data[i * frmWidth + j] = VFR->at(vecAt); vecAt++; rawdata[Cb].data[i * frmWidth + j] = VFR->at(vecAt); vecAt++; rawdata[Cr].data[i * frmWidth + j] = VFR->at(vecAt); vecAt++; } // get right-side padding (fill with junk) for (int j = vidWidth; j < frmWidth; j++) { rawdata[Y].data[i * frmWidth + j] = 0; rawdata[Cb].data[i * frmWidth + j] = 0; rawdata[Cr].data[i * frmWidth + j] = 0; } } // frame made, send through theora if (th_encode_ycbcr_in(videnc, rawdata)) { std::cerr << "Error in sending frame " << FRNO + 1 << " of " << vidframes.size() << " to Theora.\n"; throw 42; } // send theora packets into ogg while (true) { int packok = th_encode_packetout(videnc, FRNO + 1 == vidframes.size(), &vidpacket); if (packok == 0) { break; } if (packok < 0) { std::cerr << "Retrieving packet from Theora failed with error code " << packok << ".\n"; throw 42; } if (ogg_stream_packetin(&vidcont, &vidpacket)) { std::cerr << "Giving frame packet to Ogg failed.\n"; throw 42; } } // send complete pages from frame to file (we won't flush until // after all frames are accounted for, to avoid an abundance of // undersized pages) while (ogg_stream_pageout(&vidcont, &vidpage)) { writePage(); } } // take care of any remaining undersized page(s) while (ogg_stream_flush(&vidcont, &vidpage)) { writePage(); } //// Free/close/etc all relevant structures // fstream vidfile.close(); // theora items //th_encode_free(videnc); // causes a corrupted double-linked list, somehow, so you'll have to live with unfree'd memory :( th_info_clear(&vidinfo); th_comment_clear(&vidcomment); for (auto & i : rawdata) { delete[] i.data; } // ogg items ogg_packet_clear(&vidpacket); ogg_stream_clear(&vidcont); }
off_t oggedit_write_flac_metadata(DB_FILE *in, const char *fname, const off_t offset, const int num_tags, char **tags) { off_t res; char tempname[PATH_MAX] = ""; ogg_packet **headers = NULL; char *vendor = NULL; ogg_sync_state oy; ogg_sync_init(&oy); /* Original file must be writable whichever way we update it */ FILE *out = fopen(fname, "r+b"); if (!out) { res = OGGEDIT_CANNOT_UPDATE_FILE; goto cleanup; } /* See if we can write the tags packet directly into the existing file ... */ if (!(headers = metadata_block_packets(in, &oy, offset, &vendor, (int *)&res))) goto cleanup; const off_t stream_size_k = in->vfs->getlength(in) / 1000; // use file size for now const size_t metadata_size = 4 + vc_size(vendor, num_tags, tags); ptrdiff_t padding = headers[0]->bytes - metadata_size; if (stream_size_k < 1000 || padding < 0 || (headers[1] && padding > 0) || padding > stream_size_k+metadata_size) { res = open_temp_file(fname, tempname, &out); if (res) { goto cleanup; } } /* Re-pad if writing the whole file */ if (*tempname) { size_t i = 0, j = 0; while (headers[i]) { headers[j++] = headers[i]; while (headers[++i] && (headers[i]->packet[0] & 0x3F) == PADTYPE) { ogg_packet_clear(headers[i]); free(headers[i]); } } headers[j] = NULL; padding = headers[1] || stream_size_k < 900 ? 0 : stream_size_k < 10000 ? 1024 : stream_size_k < 100000 ? 8192 : 65536; } /* Write pages until we reach the correct comment header */ ogg_page og; const int flac_serial = copy_up_to_codec(in, out, &oy, &og, *tempname ? 0 : offset, offset, FLACNAME); if (flac_serial <= OGGEDIT_EOF) { res = flac_serial; goto cleanup; } if ((res = copy_up_to_header(in, out, &oy, &og, flac_serial)) <= OGGEDIT_EOF) goto cleanup; const long pageno = write_metadata_block_packets(out, flac_serial, vendor, num_tags, tags, padding, headers); if (pageno < OGGEDIT_EOF) { res = pageno; goto cleanup; } /* If we have tempfile, copy the remaining pages */ if (*tempname) { if ((res = copy_remaining_pages(in, out, &oy, flac_serial, pageno)) <= OGGEDIT_EOF) goto cleanup; if (rename(tempname, fname)) { res = OGGEDIT_RENAME_FAILED; goto cleanup; } } res = file_size(fname); cleanup: clear_header_list(headers); cleanup(in, out, &oy, vendor); if (res < OGGEDIT_OK) unlink(tempname); return res; }
off_t oggedit_write_vorbis_metadata(DB_FILE *in, const char *fname, const off_t offset, const size_t stream_size, const int num_tags, char **tags) { off_t res; char tempname[PATH_MAX] = ""; char *vendor = NULL; ogg_packet codebooks; memset(&codebooks, '\0', sizeof(codebooks)); ogg_sync_state oy; ogg_sync_init(&oy); /* Original file must be writable whichever way we update it */ FILE *out = fopen(fname, "r+b"); if (!out) { res = OGGEDIT_CANNOT_UPDATE_FILE; goto cleanup; } /* See if we can write the tags packet directly into the existing file ... */ const ptrdiff_t tags_packet_size = check_vorbis_headers(in, &oy, offset, &vendor, &codebooks); if (tags_packet_size <= OGGEDIT_EOF) { res = tags_packet_size; goto cleanup; } const size_t metadata_size = strlen(VCMAGIC) + vc_size(vendor, num_tags, tags) + 1; ptrdiff_t padding = tags_packet_size - metadata_size; const off_t file_size_k = in->vfs->getlength(in) / 1000; const size_t stream_size_k = stream_size ? stream_size / 1000 : file_size_k; if (file_size_k < 100 || padding < 0 || padding > file_size_k/10+stream_size_k+metadata_size) { res = open_temp_file(fname, tempname, &out); if (res) { goto cleanup; } } /* Re-pad if writing the whole file */ if (*tempname) padding = stream_size_k < 90 ? 0 : stream_size_k < 1000 ? 128 : stream_size_k < 10000 ? 1024 : 8192; /* Write pages until the correct comment header */ ogg_page og; int64_t vorbis_serial = copy_up_to_codec(in, out, &oy, &og, *tempname ? 0 : offset, offset, VORBISNAME); if (vorbis_serial <= OGGEDIT_EOF) { res = vorbis_serial; goto cleanup; } vorbis_serial = copy_up_to_header(in, out, &oy, &og, vorbis_serial); if (vorbis_serial <= OGGEDIT_EOF) { res = vorbis_serial; goto cleanup; } const long pageno = write_vorbis_tags(out, vorbis_serial, vendor, num_tags, tags, padding, &codebooks); if (pageno < OGGEDIT_EOF) { res = pageno; goto cleanup; } /* If we have tempfile, copy the remaining pages */ if (*tempname) { vorbis_serial = copy_remaining_pages(in, out, &oy, vorbis_serial, pageno); if (vorbis_serial <= OGGEDIT_EOF) { res = vorbis_serial; goto cleanup; } if (rename(tempname, fname)) { res = OGGEDIT_RENAME_FAILED; goto cleanup; } } res = file_size(fname); cleanup: ogg_packet_clear(&codebooks); cleanup(in, out, &oy, vendor); if (res < OGGEDIT_OK) unlink(tempname); return res; }
int main() { /* We need an Ogg stream to write to */ ogg_stream_state os; ogg_packet op; /* First, a kate_info structure needs to be created and setup for the stream to create. A kate_comment structure also has to be created. Information from both of these will get encoded into the stream headers. Last, we also need a kate_state structure, which will be initialized later. */ kate_info ki; kate_comment kc; kate_state k; kate_info_init(&ki); kate_comment_init(&kc); /* The most important part of the kate_info structure on encoding is the granule encoding information, which describes how granules and time are mapped. Here, we map one granule to one millisecond. */ ki.granule_shift=32; ki.gps_numerator=1000; ki.gps_denominator=1; /* With that done, we can initialize libkate for encoding, and initialize libogg as well: */ kate_encode_init(&k,&ki); ogg_stream_init(&os,0x12345678); /* for the benefit of windows, which mangles data otherwise */ set_binary_file(stdout); /* Before you can create events, headers need to be sent. Here, we'll just send the headers directly, but you will usually want to add regions, styles, etc to the headers before doing so: */ while (kate_ogg_encode_headers(&k,&kc,&op)==0) { ogg_stream_packetin(&os,&op); ogg_packet_clear(&op); } flush_page(&os); /* Events can now be created, and we'll just create and send a single one here, starting at time 10 seconds, and stopping at time 15 seconds. */ #define text "Hello, world!" kate_ogg_encode_text(&k,10.0,15.0,text,strlen(text)+1,&op); ogg_stream_packetin(&os,&op); ogg_packet_clear(&op); flush_page(&os); /* When we're done, we can tell libkate so an "end of stream" packet will be generated, and clear the resources we've been using: */ kate_ogg_encode_finish(&k,-1,&op); ogg_stream_packetin(&os,&op); ogg_packet_clear(&op); flush_page(&os); ogg_stream_clear(&os); kate_clear(&k); kate_info_clear(&ki); kate_comment_clear(&kc); /* That's it, we now have created a full kate stream. You may now want to decode it, or multiplex it with a Theora video, etc. */ return 0; }
static av_cold int encode_init(AVCodecContext* avc_context) { theora_info t_info; theora_comment t_comment; ogg_packet o_packet; unsigned int offset; TheoraContext *h = avc_context->priv_data; /* Set up the theora_info struct */ theora_info_init( &t_info ); t_info.width = FFALIGN(avc_context->width, 16); t_info.height = FFALIGN(avc_context->height, 16); t_info.frame_width = avc_context->width; t_info.frame_height = avc_context->height; t_info.offset_x = 0; t_info.offset_y = avc_context->height & 0xf; /* Swap numerator and denominator as time_base in AVCodecContext gives the * time period between frames, but theora_info needs the framerate. */ t_info.fps_numerator = avc_context->time_base.den; t_info.fps_denominator = avc_context->time_base.num; if (avc_context->sample_aspect_ratio.num != 0) { t_info.aspect_numerator = avc_context->sample_aspect_ratio.num; t_info.aspect_denominator = avc_context->sample_aspect_ratio.den; } else { t_info.aspect_numerator = 1; t_info.aspect_denominator = 1; } t_info.colorspace = OC_CS_UNSPECIFIED; t_info.pixelformat = OC_PF_420; t_info.target_bitrate = avc_context->bit_rate; t_info.keyframe_frequency = avc_context->gop_size; t_info.keyframe_frequency_force = avc_context->gop_size; t_info.keyframe_mindistance = avc_context->keyint_min; t_info.quality = 0; t_info.quick_p = 1; t_info.dropframes_p = 0; t_info.keyframe_auto_p = 1; t_info.keyframe_data_target_bitrate = t_info.target_bitrate * 1.5; t_info.keyframe_auto_threshold = 80; t_info.noise_sensitivity = 1; t_info.sharpness = 0; /* Now initialise libtheora */ if (theora_encode_init( &(h->t_state), &t_info ) != 0) { av_log(avc_context, AV_LOG_ERROR, "theora_encode_init failed\n"); return -1; } /* Clear up theora_info struct */ theora_info_clear( &t_info ); /* Output first header packet consisting of theora header, comment, and tables. Each one is prefixed with a 16bit size, then they are concatenated together into ffmpeg's extradata. */ offset = 0; /* Header */ theora_encode_header( &(h->t_state), &o_packet ); if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { return -1; } /* Comment */ theora_comment_init( &t_comment ); theora_encode_comment( &t_comment, &o_packet ); if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { return -1; } /* Clear up theora_comment struct before we reset the packet */ theora_comment_clear( &t_comment ); /* And despite documentation to the contrary, theora_comment_clear * does not release the packet */ ogg_packet_clear(&o_packet); /* Tables */ theora_encode_tables( &(h->t_state), &o_packet ); if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { return -1; } /* Set up the output AVFrame */ avc_context->coded_frame= avcodec_alloc_frame(); return 0; }
void ogg_packet_holder::clear() { ogg_packet_clear(&value); }
ogg_packet_holder::~ogg_packet_holder() { ogg_packet_clear(&value); }