Пример #1
0
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);
}
Пример #2
0
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;
};
Пример #3
0
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;
}
Пример #4
0
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);
    }
}
Пример #5
0
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);
}
Пример #6
0
/* 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;
}
Пример #7
0
    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);
    }
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
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;
}
Пример #12
0
void ogg_packet_holder::clear() {
  ogg_packet_clear(&value);
}
Пример #13
0
ogg_packet_holder::~ogg_packet_holder() {
  ogg_packet_clear(&value);
}