int krad_theora_encoder_write (krad_theora_encoder_t *krad_theora, uint8_t **packet, int *keyframe) { int ret; int key; if (krad_theora->update_config) { th_encode_ctl (krad_theora->encoder, TH_ENCCTL_SET_QUALITY, &krad_theora->quality, sizeof(int)); krad_theora->update_config = 0; } ret = th_encode_ycbcr_in (krad_theora->encoder, krad_theora->ycbcr); if (ret != 0) { failfast ("krad_theora_encoder_write th_encode_ycbcr_in failed! %d", ret); } // Note: Currently the encoder operates in a one-frame-in, // one-packet-out manner. However, this may be changed in the future. ret = th_encode_packetout (krad_theora->encoder, krad_theora->finish, &krad_theora->packet); if (ret < 1) { failfast ("krad_theora_encoder_write th_encode_packetout failed! %d", ret); } *packet = krad_theora->packet.packet; key = th_packet_iskeyframe (&krad_theora->packet); *keyframe = key; if (*keyframe == -1) { failfast ("krad_theora_encoder_write th_packet_iskeyframe failed! %d", *keyframe); } if (key) { //printk ("its a keyframe\n"); } // Double check //ogg_packet test_packet; //ret = th_encode_packetout (krad_theora->encoder, // krad_theora->finish, &test_packet); //if (ret != 0) { // printf("krad_theora_encoder_write th_encode_packetout // offerd up an extra packet! %d\n", ret); // exit(1); //} krad_theora->frames++; krad_theora->bytes += krad_theora->packet.bytes; return krad_theora->packet.bytes; }
int theora_packet_iskeyframe(ogg_packet *_op){ return th_packet_iskeyframe(_op); }
void TheoraState::ReconstructTheoraGranulepos() { if (mUnstamped.Length() == 0) { return; } ogg_int64_t lastGranulepos = mUnstamped[mUnstamped.Length() - 1]->granulepos; NS_ASSERTION(lastGranulepos != -1, "Must know last granulepos"); // Reconstruct the granulepos (and thus timestamps) of the decoded // frames. Granulepos are stored as ((keyframe<<shift)+offset). We // know the granulepos of the last frame in the list, so we can infer // the granulepos of the intermediate frames using their frame numbers. ogg_int64_t shift = mInfo.keyframe_granule_shift; ogg_int64_t version_3_2_1 = TheoraVersion(&mInfo,3,2,1); ogg_int64_t lastFrame = th_granule_frame(mCtx, lastGranulepos) + version_3_2_1; ogg_int64_t firstFrame = lastFrame - mUnstamped.Length() + 1; // Until we encounter a keyframe, we'll assume that the "keyframe" // segment of the granulepos is the first frame, or if that causes // the "offset" segment to overflow, we assume the required // keyframe is maximumally offset. Until we encounter a keyframe // the granulepos will probably be wrong, but we can't decode the // frame anyway (since we don't have its keyframe) so it doesn't really // matter. ogg_int64_t keyframe = lastGranulepos >> shift; // The lastFrame, firstFrame, keyframe variables, as well as the frame // variable in the loop below, store the frame number for Theora // version >= 3.2.1 streams, and store the frame index for Theora // version < 3.2.1 streams. for (uint32_t i = 0; i < mUnstamped.Length() - 1; ++i) { ogg_int64_t frame = firstFrame + i; ogg_int64_t granulepos; ogg_packet* packet = mUnstamped[i]; bool isKeyframe = th_packet_iskeyframe(packet) == 1; if (isKeyframe) { granulepos = frame << shift; keyframe = frame; } else if (frame >= keyframe && frame - keyframe < ((ogg_int64_t)1 << shift)) { // (frame - keyframe) won't overflow the "offset" segment of the // granulepos, so it's safe to calculate the granulepos. granulepos = (keyframe << shift) + (frame - keyframe); } else { // (frame - keyframeno) will overflow the "offset" segment of the // granulepos, so we take "keyframe" to be the max possible offset // frame instead. ogg_int64_t k = std::max(frame - (((ogg_int64_t)1 << shift) - 1), version_3_2_1); granulepos = (k << shift) + (frame - k); } // Theora 3.2.1+ granulepos store frame number [1..N], so granulepos // should be > 0. // Theora 3.2.0 granulepos store the frame index [0..(N-1)], so // granulepos should be >= 0. NS_ASSERTION(granulepos >= version_3_2_1, "Invalid granulepos for Theora version"); // Check that the frame's granule number is one more than the // previous frame's. NS_ASSERTION(i == 0 || th_granule_frame(mCtx, granulepos) == th_granule_frame(mCtx, mUnstamped[i-1]->granulepos) + 1, "Granulepos calculation is incorrect!"); packet->granulepos = granulepos; } // Check that the second to last frame's granule number is one less than // the last frame's (the known granule number). If not our granulepos // recovery missed a beat. NS_ASSERTION(mUnstamped.Length() < 2 || th_granule_frame(mCtx, mUnstamped[mUnstamped.Length()-2]->granulepos) + 1 == th_granule_frame(mCtx, lastGranulepos), "Granulepos recovery should catch up with packet->granulepos!"); }