예제 #1
0
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;
}
예제 #2
0
int theora_packet_iskeyframe(ogg_packet *_op){
  return th_packet_iskeyframe(_op);
}
예제 #3
0
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!");
}