Exemplo n.º 1
0
nsTheoraState::nsTheoraState(ogg_page* aBosPage) :
  nsOggCodecState(aBosPage, true),
  mSetup(0),
  mCtx(0),
  mPixelAspectRatio(0)
{
  MOZ_COUNT_CTOR(nsTheoraState);
  th_info_init(&mInfo);
  th_comment_init(&mComment);
}
Exemplo n.º 2
0
static int
noop_test_comments ()
{
  th_comment tc;

  INFO ("+ Initializing th_comment struct");
  th_comment_init (&tc);

  INFO ("+ Clearing empty th_comment struct")
  th_comment_clear (&tc);

  return 0;
}
Exemplo n.º 3
0
void CHolly_Theora_Video::WriteHeader()
{
	th_comment       tc;
	th_comment_init( &tc );
	tc.vendor = (char *)"Holly";

	ogg_packet header;
	ogg_packet header_comm;
	ogg_packet header_code;

	while ( th_encode_flushheader( m_Encoder, &tc, &header ) > 0 )
	{
		Encoder()->Container()->WriteHeader( this, &header );
	}
}
Exemplo n.º 4
0
static GstStateChangeReturn
theora_parse_change_state (GstElement * element, GstStateChange transition)
{
  GstTheoraParse *parse = GST_THEORA_PARSE (element);
  GstStateChangeReturn ret;
  gint i;

  switch (transition) {
    case GST_STATE_CHANGE_READY_TO_PAUSED:
      th_info_init (&parse->info);
      th_comment_init (&parse->comment);
      parse->send_streamheader = TRUE;
      parse->buffer_queue = g_queue_new ();
      parse->event_queue = g_queue_new ();
      parse->prev_keyframe = -1;
      parse->prev_frame = -1;
      parse->granule_offset = 0;
      break;
    default:
      break;
  }

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

  switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      th_info_clear (&parse->info);
      th_comment_clear (&parse->comment);
      theora_parse_clear_queue (parse);
      g_queue_free (parse->buffer_queue);
      g_queue_free (parse->event_queue);
      parse->buffer_queue = NULL;
      for (i = 0; i < 3; i++) {
        if (parse->streamheader[i]) {
          gst_buffer_unref (parse->streamheader[i]);
          parse->streamheader[i] = NULL;
        }
      }
      parse->streamheader_received = FALSE;
      break;
    default:
      break;
  }

  return ret;
}
Exemplo n.º 5
0
krad_theora_decoder_t *krad_theora_decoder_create(unsigned char *header1, int header1len, unsigned char *header2, int header2len, unsigned char *header3, int header3len) {

	krad_theora_decoder_t *krad_theora;
	
	krad_theora = calloc(1, sizeof(krad_theora_decoder_t));

	krad_theora->granulepos = -1;

	th_comment_init(&krad_theora->comment);
	th_info_init(&krad_theora->info);

	krad_theora->packet.packet = header1;
	krad_theora->packet.bytes = header1len;
	krad_theora->packet.b_o_s = 1;
	krad_theora->packet.packetno = 1;
	th_decode_headerin(&krad_theora->info, &krad_theora->comment, &krad_theora->setup_info, &krad_theora->packet);
	//printf("x is %d len is %d\n", x, header1len);

	krad_theora->packet.packet = header2;
	krad_theora->packet.bytes = header2len;
	krad_theora->packet.b_o_s = 0;
	krad_theora->packet.packetno = 2;
	th_decode_headerin(&krad_theora->info, &krad_theora->comment, &krad_theora->setup_info, &krad_theora->packet);
	//printf("x is %d len is %d\n", x, header2len);

	krad_theora->packet.packet = header3;
	krad_theora->packet.bytes = header3len;
	krad_theora->packet.packetno = 3;
	th_decode_headerin(&krad_theora->info, &krad_theora->comment, &krad_theora->setup_info, &krad_theora->packet);

	printf("Theora %dx%d %.02f fps video\n Encoded frame content is %dx%d with %dx%d offset\n",
		   krad_theora->info.frame_width, krad_theora->info.frame_height, 
		   (double)krad_theora->info.fps_numerator/krad_theora->info.fps_denominator,
		   krad_theora->info.pic_width, krad_theora->info.pic_height, krad_theora->info.pic_x, krad_theora->info.pic_y);


	krad_theora->decoder = th_decode_alloc(&krad_theora->info, krad_theora->setup_info);

	th_setup_free(krad_theora->setup_info);

	return krad_theora;

}
Exemplo n.º 6
0
static gboolean
theora_enc_start (GstVideoEncoder * benc)
{
    GstTheoraEnc *enc;

    GST_DEBUG_OBJECT (benc, "start: init theora");
    enc = GST_THEORA_ENC (benc);

    th_info_init (&enc->info);
    th_comment_init (&enc->comment);
    enc->packetno = 0;

    if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
        GError *err = NULL;

        if (!enc->multipass_cache_file) {
            GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
            return FALSE;
        }
        enc->multipass_cache_fd =
            g_io_channel_new_file (enc->multipass_cache_file,
                                   (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"), &err);

        if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
            enc->multipass_cache_adapter = gst_adapter_new ();

        if (!enc->multipass_cache_fd) {
            GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
                               ("Failed to open multipass cache file: %s", err->message));
            g_error_free (err);
            return FALSE;
        }

        g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
    }

    return TRUE;
}
Exemplo n.º 7
0
static int OpenCommon( vlc_object_t *p_this, bool b_packetizer )
{
    decoder_t *p_dec = (decoder_t*)p_this;
    decoder_sys_t *p_sys;

    if( p_dec->fmt_in.i_codec != VLC_CODEC_THEORA )
    {
        return VLC_EGENERIC;
    }

    /* Allocate the memory needed to store the decoder's structure */
    if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
        return VLC_ENOMEM;
    p_sys->b_packetizer = b_packetizer;
    p_sys->b_has_headers = false;
    p_sys->i_pts = VLC_TICK_INVALID;
    p_sys->b_decoded_first_keyframe = false;
    p_sys->tcx = NULL;

    if( b_packetizer )
    {
        p_dec->fmt_out.i_codec = VLC_CODEC_THEORA;
        p_dec->pf_packetize = Packetize;
    }
    else
    {
        p_dec->fmt_out.i_codec = VLC_CODEC_I420;
        p_dec->pf_decode = DecodeVideo;
    }
    p_dec->pf_flush = Flush;

    /* Init supporting Theora structures needed in header parsing */
    th_comment_init( &p_sys->tc );
    th_info_init( &p_sys->ti );

    return VLC_SUCCESS;
}
Exemplo n.º 8
0
void
gobee_theora_resize(int w, int h, int _stride, int sock, struct sockaddr *addr,
    int addrlen)
{
  time_t stamp = time(NULL);

  th_info_init(&tinfo);
  th_comment_init(&tcmnt);

  tinfo.frame_width = w;
  tinfo.frame_height = h;
  tinfo.pic_width = w;
  tinfo.pic_height = h;
  tinfo.pic_y = 0;
  tinfo.pic_x = 0;
  tinfo.fps_numerator = 30;
  tinfo.fps_denominator = 1;
  tinfo.aspect_denominator = 1;
  tinfo.aspect_numerator = 1;
  tinfo.target_bitrate = 200000;
  tinfo.quality = 12;
  tinfo.colorspace = TH_CS_ITU_REC_470BG; //TH_CS_UNSPECIFIED;
  tinfo.pixel_fmt = TH_PF_420;
  tinfo.keyframe_granule_shift = 100;
  tcmnt.vendor = "qqq";

  // recreate encoder
  if (tctx)
    th_encode_free(tctx);
  tctx = th_encode_alloc(&tinfo);

  __gobee_yuv_resize(&s_ycbcr, w, h);
  printf("sending...\n");
  __gobee_theora_send_headers(sock, addr, addrlen, stamp);
  printf("sent...\n");

}
Exemplo n.º 9
0
static av_cold int encode_init(AVCodecContext* avc_context)
{
    th_info t_info;
    th_comment t_comment;
    ogg_packet o_packet;
    unsigned int offset;
    TheoraContext *h = avc_context->priv_data;
    uint32_t gop_size = avc_context->gop_size;

    /* Set up the theora_info struct */
    th_info_init(&t_info);
    t_info.frame_width  = FFALIGN(avc_context->width,  16);
    t_info.frame_height = FFALIGN(avc_context->height, 16);
    t_info.pic_width    = avc_context->width;
    t_info.pic_height   = avc_context->height;
    t_info.pic_x        = 0;
    t_info.pic_y        = 0;
    /* 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) {
        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;
    }

    if (avc_context->color_primaries == AVCOL_PRI_BT470M)
        t_info.colorspace = TH_CS_ITU_REC_470M;
    else if (avc_context->color_primaries == AVCOL_PRI_BT470BG)
        t_info.colorspace = TH_CS_ITU_REC_470BG;
    else
        t_info.colorspace = TH_CS_UNSPECIFIED;

    if (avc_context->pix_fmt == AV_PIX_FMT_YUV420P)
        t_info.pixel_fmt = TH_PF_420;
    else if (avc_context->pix_fmt == AV_PIX_FMT_YUV422P)
        t_info.pixel_fmt = TH_PF_422;
    else if (avc_context->pix_fmt == AV_PIX_FMT_YUV444P)
        t_info.pixel_fmt = TH_PF_444;
    else {
        av_log(avc_context, AV_LOG_ERROR, "Unsupported pix_fmt\n");
        return -1;
    }
    av_pix_fmt_get_chroma_sub_sample(avc_context->pix_fmt,
                                     &h->uv_hshift, &h->uv_vshift);

    if (avc_context->flags & CODEC_FLAG_QSCALE) {
        /* to be constant with the libvorbis implementation, clip global_quality to 0 - 10
           Theora accepts a quality parameter p, which is:
                * 0 <= p <=63
                * an int value
         */
        t_info.quality        = av_clipf(avc_context->global_quality / (float)FF_QP2LAMBDA, 0, 10) * 6.3;
        t_info.target_bitrate = 0;
    } else {
        t_info.target_bitrate = avc_context->bit_rate;
        t_info.quality        = 0;
    }

    /* Now initialise libtheora */
    h->t_state = th_encode_alloc(&t_info);
    if (!h->t_state) {
        av_log(avc_context, AV_LOG_ERROR, "theora_encode_init failed\n");
        return -1;
    }

    h->keyframe_mask = (1 << t_info.keyframe_granule_shift) - 1;
    /* Clear up theora_info struct */
    th_info_clear(&t_info);

    if (th_encode_ctl(h->t_state, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
                      &gop_size, sizeof(gop_size))) {
        av_log(avc_context, AV_LOG_ERROR, "Error setting GOP size\n");
        return -1;
    }

    // need to enable 2 pass (via TH_ENCCTL_2PASS_) before encoding headers
    if (avc_context->flags & CODEC_FLAG_PASS1) {
        if (get_stats(avc_context, 0))
            return -1;
    } else if (avc_context->flags & CODEC_FLAG_PASS2) {
        if (submit_stats(avc_context))
            return -1;
    }

    /*
        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 libavcodec's extradata.
    */
    offset = 0;

    /* Headers */
    th_comment_init(&t_comment);

    while (th_encode_flushheader(h->t_state, &t_comment, &o_packet))
        if (concatenate_packet(&offset, avc_context, &o_packet))
            return -1;

    th_comment_clear(&t_comment);

    /* Set up the output AVFrame */
    avc_context->coded_frame = av_frame_alloc();

    return 0;
}
Exemplo n.º 10
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);
    }
Exemplo n.º 11
0
bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) {
	close();

	_fileStream = stream;

	// start up Ogg stream synchronization layer
	ogg_sync_init(&_oggSync);

	// init supporting Vorbis structures needed in header parsing
	vorbis_info_init(&_vorbisInfo);
	vorbis_comment vorbisComment;
	vorbis_comment_init(&vorbisComment);

	// init supporting Theora structures needed in header parsing
	th_info theoraInfo;
	th_info_init(&theoraInfo);
	th_comment theoraComment;
	th_comment_init(&theoraComment);
	th_setup_info *theoraSetup = 0;

	uint theoraPackets = 0, vorbisPackets = 0;

	// Ogg file open; parse the headers
	// Only interested in Vorbis/Theora streams
	bool foundHeader = false;
	while (!foundHeader) {
		int ret = bufferData();

		if (ret == 0)
			break; // FIXME: Shouldn't this error out?

		while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) {
			ogg_stream_state test;

			// is this a mandated initial header? If not, stop parsing
			if (!ogg_page_bos(&_oggPage)) {
				// don't leak the page; get it into the appropriate stream
				queuePage(&_oggPage);
				foundHeader = true;
				break;
			}

			ogg_stream_init(&test, ogg_page_serialno(&_oggPage));
			ogg_stream_pagein(&test, &_oggPage);
			ogg_stream_packetout(&test, &_oggPacket);

			// identify the codec: try theora
			if (theoraPackets == 0 && th_decode_headerin(&theoraInfo, &theoraComment, &theoraSetup, &_oggPacket) >= 0) {
				// it is theora
				memcpy(&_theoraOut, &test, sizeof(test));
				theoraPackets = 1;
				_hasVideo = true;
			} else if (vorbisPackets == 0 && vorbis_synthesis_headerin(&_vorbisInfo, &vorbisComment, &_oggPacket) >= 0) {
				// it is vorbis
				memcpy(&_vorbisOut, &test, sizeof(test));
				vorbisPackets = 1;
				_hasAudio = true;
			} else {
				// whatever it is, we don't care about it
				ogg_stream_clear(&test);
			}
		}
		// fall through to non-bos page parsing
	}

	// we're expecting more header packets.
	while ((theoraPackets && theoraPackets < 3) || (vorbisPackets && vorbisPackets < 3)) {
		int ret;

		// look for further theora headers
		while (theoraPackets && (theoraPackets < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) {
			if (ret < 0)
				error("Error parsing Theora stream headers; corrupt stream?");

			if (!th_decode_headerin(&theoraInfo, &theoraComment, &theoraSetup, &_oggPacket))
				error("Error parsing Theora stream headers; corrupt stream?");

			theoraPackets++;
		}

		// look for more vorbis header packets
		while (vorbisPackets && (vorbisPackets < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) {
			if (ret < 0)
				error("Error parsing Vorbis stream headers; corrupt stream?");

			if (vorbis_synthesis_headerin(&_vorbisInfo, &vorbisComment, &_oggPacket))
				error("Error parsing Vorbis stream headers; corrupt stream?");

			vorbisPackets++;

			if (vorbisPackets == 3)
				break;
		}

		// The header pages/packets will arrive before anything else we
		// care about, or the stream is not obeying spec

		if (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) {
			queuePage(&_oggPage); // demux into the appropriate stream
		} else {
			ret = bufferData(); // someone needs more data

			if (ret == 0)
				error("End of file while searching for codec headers.");
		}
	}

	// And now we have it all. Initialize decoders next
	if (_hasVideo) {
		_videoTrack = new TheoraVideoTrack(getDefaultHighColorFormat(), theoraInfo, theoraSetup);
		addTrack(_videoTrack);
	}

	th_info_clear(&theoraInfo);
	th_comment_clear(&theoraComment);
	th_setup_free(theoraSetup);

	if (_hasAudio) {
		_audioTrack = new VorbisAudioTrack(_soundType, _vorbisInfo);

		// Get enough audio data to start us off
		while (!_audioTrack->hasAudio()) {
			// Queue more data
			bufferData();
			while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0)
				queuePage(&_oggPage);

			queueAudio();
		}

		addTrack(_audioTrack);
	}

	vorbis_comment_clear(&vorbisComment);

	return true;
}
Exemplo n.º 12
0
krad_theora_decoder_t *
krad_theora_decoder_create (krad_codec_header_t *header) {

    krad_theora_decoder_t *krad_theora;

    krad_theora = calloc(1, sizeof(krad_theora_decoder_t));

    krad_theora->granulepos = -1;

    th_comment_init(&krad_theora->comment);
    th_info_init(&krad_theora->info);
    /*
      krad_theora->packet.packet = header->header[0];
      krad_theora->packet.bytes = header->header_size[0];
      krad_theora->packet.b_o_s = 1;
      krad_theora->packet.packetno = 1;
      th_decode_headerin (&krad_theora->info, &krad_theora->comment,
                          &krad_theora->setup_info, &krad_theora->packet);

      krad_theora->packet.packet = header->header[1];
      krad_theora->packet.bytes = header->header_size[1];
      krad_theora->packet.b_o_s = 0;
      krad_theora->packet.packetno = 2;
      th_decode_headerin (&krad_theora->info, &krad_theora->comment,
                          &krad_theora->setup_info, &krad_theora->packet);

      krad_theora->packet.packet = header->header[2];
      krad_theora->packet.bytes = header->header_size[2];
      krad_theora->packet.packetno = 3;
      th_decode_headerin (&krad_theora->info, &krad_theora->comment,
                          &krad_theora->setup_info, &krad_theora->packet);

      krad_theora->color_depth = PIX_FMT_YUV420P;
      if (krad_theora->info.pixel_fmt == TH_PF_422) {
        krad_theora->color_depth = PIX_FMT_YUV422P;
        printk ("Theora color depth 422");
      }
      if (krad_theora->info.pixel_fmt == TH_PF_444) {
        krad_theora->color_depth = PIX_FMT_YUV444P;
        printk ("Theora color depth 444");
      }
    */
    printk ("Theora %dx%d %.02f fps video\n Encoded frame content is %dx%d with %dx%d offset",
            krad_theora->info.frame_width, krad_theora->info.frame_height,
            (double)krad_theora->info.fps_numerator/krad_theora->info.fps_denominator,
            krad_theora->info.pic_width, krad_theora->info.pic_height,
            krad_theora->info.pic_x, krad_theora->info.pic_y);


    krad_theora->offset_y = krad_theora->info.pic_y;
    krad_theora->offset_x = krad_theora->info.pic_x;

    krad_theora->width = krad_theora->info.pic_width;
    krad_theora->height = krad_theora->info.pic_height;

    krad_theora->decoder = th_decode_alloc (&krad_theora->info,
                                            krad_theora->setup_info);

    th_setup_free(krad_theora->setup_info);

    return krad_theora;
}
Exemplo n.º 13
0
krad_theora_encoder_t *krad_theora_encoder_create (int width, int height,
        int fps_numerator,
        int fps_denominator,
        int color_depth,
        int quality) {

    krad_theora_encoder_t *krad_theora;

    krad_theora = calloc (1, sizeof(krad_theora_encoder_t));

    krad_theora->width = width;
    krad_theora->height = height;
    krad_theora->quality = quality;
    krad_theora->color_depth = color_depth;

    th_info_init (&krad_theora->info);
    th_comment_init (&krad_theora->comment);

    krad_theora->info.frame_width = krad_theora->width;
    if (krad_theora->width % 16) {
        krad_theora->info.frame_width += 16 - (krad_theora->width % 16);
    }
    krad_theora->info.frame_height = krad_theora->height;
    if (krad_theora->height % 16) {
        krad_theora->info.frame_height += 16 - (krad_theora->height % 16);
    }
    krad_theora->info.pic_width = krad_theora->width;
    krad_theora->info.pic_height = krad_theora->height;
    krad_theora->info.pic_x = 0;
    krad_theora->info.pic_y = 0;
    krad_theora->info.aspect_denominator = 1;
    krad_theora->info.aspect_numerator = 1;
    krad_theora->info.target_bitrate = 0;
    krad_theora->info.quality = krad_theora->quality;
    if (krad_theora->color_depth == PIX_FMT_YUV420P) {
        krad_theora->info.pixel_fmt = TH_PF_420;
    }
    if (krad_theora->color_depth == PIX_FMT_YUV422P) {
        krad_theora->info.pixel_fmt = TH_PF_422;
    }
    if (krad_theora->color_depth == PIX_FMT_YUV444P) {
        krad_theora->info.pixel_fmt = TH_PF_444;
    }
    krad_theora->keyframe_shift = krad_theora->info.keyframe_granule_shift;

    printk ("Loading Theora encoder version %s", th_version_string());
    printk ("Theora keyframe shift %d", krad_theora->keyframe_shift);

    krad_theora->info.fps_numerator = fps_numerator;
    krad_theora->info.fps_denominator = fps_denominator;
    //krad_theora->keyframe_distance = 30;

    krad_theora->encoder = th_encode_alloc (&krad_theora->info);

    //th_encode_ctl (krad_theora->encoder,
    //TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
    // &krad_theora->keyframe_distance, sizeof(int));
    //printk ("Theora keyframe max distance %u\n",
    //  krad_theora->keyframe_distance);

    /*
    if (strstr(krad_system_cpu_type(), "x86") == NULL) {
      //FOR ARM Realtime
      th_encode_ctl (krad_theora->encoder,
                     TH_ENCCTL_GET_SPLEVEL_MAX,
                     &krad_theora->speed,
                     sizeof(int));
      printk ("Theora encoder speed: %d quality: %d",
              krad_theora->speed, krad_theora->quality);
      th_encode_ctl (krad_theora->encoder, TH_ENCCTL_SET_SPLEVEL,
                     &krad_theora->speed, sizeof(int));
    } else {
      //FOR x86 Realtime
      th_encode_ctl (krad_theora->encoder,
                     TH_ENCCTL_GET_SPLEVEL_MAX,
                     &krad_theora->speed, sizeof(int));
      if ((krad_theora->width <= 1280) && (krad_theora->height <= 720)) {
        krad_theora->speed -= 1;
      }
      printk ("Theora encoder speed: %d quality: %d",
              krad_theora->speed, krad_theora->quality);
      th_encode_ctl (krad_theora->encoder,
                     TH_ENCCTL_SET_SPLEVEL,
                     &krad_theora->speed, sizeof(int));
    }
    */
    /*
      while (th_encode_flushheader ( krad_theora->encoder,
                                     &krad_theora->comment,
                                     &krad_theora->packet) > 0) {

        krad_theora->header_combined_size += krad_theora->packet.bytes;
        krad_theora->header[krad_theora->header_count] =
          malloc (krad_theora->packet.bytes);
        memcpy (krad_theora->header[krad_theora->header_count],
                krad_theora->packet.packet,
                krad_theora->packet.bytes);
        krad_theora->header_len[krad_theora->header_count] =
          krad_theora->packet.bytes;
        krad_theora->header_count++;

        //printk ("krad_theora_encoder_create th_encode_flushheader got
        // header packet %"PRIi64" which is %ld bytes\n",
        //    krad_theora->packet.packetno, krad_theora->packet.bytes);
      }

      //printk ("krad_theora_encoder_create Got %d header packets\n",
      //      krad_theora->header_count);

      krad_theora->header_combined = calloc (1, krad_theora->header_combined_size + 10);

      krad_theora->header_combined[0] = 0x02;
      krad_theora->header_combined_pos++;

      //printk ("main is %ld\n", vorbis->header_main.bytes);
      if (krad_theora->header_len[0] > 255) {
        failfast ("theora mainheader to long for code");
      }

      krad_theora->demented = krad_theora->header_len[0];
      krad_theora->header_combined[1] = (char)krad_theora->demented;
      krad_theora->header_combined_pos++;

      //printk ("comments is %ld\n", vorbis->header_comments.bytes);
      if (krad_theora->header_len[1] > 255) {
        failfast ("theora comments header to long for code");
      }

      krad_theora->demented = krad_theora->header_len[1];
      krad_theora->header_combined[2] = (char)krad_theora->demented;
      krad_theora->header_combined_pos++;

      krad_theora->header_combined_size += 3;

      memcpy (krad_theora->header_combined + krad_theora->header_combined_pos,
              krad_theora->header[0],
              krad_theora->header_len[0]);
      krad_theora->header_combined_pos += krad_theora->header_len[0];

      //printf("main is %ld bytes headerpos is  %d \n",
      //vorbis->header_main.bytes, vorbis->headerpos);

      memcpy (krad_theora->header_combined + krad_theora->header_combined_pos,
              krad_theora->header[1],
              krad_theora->header_len[1]);
      krad_theora->header_combined_pos += krad_theora->header_len[1];

      //printf("comments is %ld bytes headerpos is  %d \n",
      //vorbis->header_comments.bytes, vorbis->headerpos);

      memcpy (krad_theora->header_combined + krad_theora->header_combined_pos,
              krad_theora->header[2],
              krad_theora->header_len[2]);
      krad_theora->header_combined_pos += krad_theora->header_len[2];
      krad_theora->krad_codec_header.codec = THEORA;
      krad_theora->krad_codec_header.header[0] = krad_theora->header[0];
      krad_theora->krad_codec_header.header_size[0] = krad_theora->header_len[0];
      krad_theora->krad_codec_header.header[1] = krad_theora->header[1];
      krad_theora->krad_codec_header.header_size[1] = krad_theora->header_len[1];
      krad_theora->krad_codec_header.header[2] = krad_theora->header[2];
      krad_theora->krad_codec_header.header_size[2] = krad_theora->header_len[2];

      krad_theora->krad_codec_header.header_combined = krad_theora->header_combined;
      krad_theora->krad_codec_header.header_combined_size = krad_theora->header_combined_size;
      krad_theora->krad_codec_header.header_count = 3;

      krad_theora->ycbcr[0].stride =  krad_theora->info.frame_width;
      krad_theora->ycbcr[0].width =  krad_theora->info.frame_width;
      krad_theora->ycbcr[0].height =  krad_theora->info.frame_height;

      krad_theora->ycbcr[0].data = calloc(1, krad_theora->info.frame_width * krad_theora->info.frame_height);

      if (krad_theora->color_depth == PIX_FMT_YUV420P) {
        krad_theora->ycbcr[1].stride = krad_theora->info.frame_width / 2;
        krad_theora->ycbcr[1].width = krad_theora->info.frame_width / 2;
        krad_theora->ycbcr[1].height = krad_theora->info.frame_height / 2;
        krad_theora->ycbcr[2].stride = krad_theora->info.frame_width / 2;
        krad_theora->ycbcr[2].width = krad_theora->info.frame_width / 2;
        krad_theora->ycbcr[2].height = krad_theora->info.frame_height / 2;

        krad_theora->ycbcr[1].data = calloc(1, ((krad_theora->info.frame_width / 2) * (krad_theora->info.frame_height / 2)));
        krad_theora->ycbcr[2].data = calloc(1, ((krad_theora->info.frame_width / 2) * (krad_theora->info.frame_height / 2)));
      }
      if (krad_theora->color_depth == PIX_FMT_YUV422P) {
        krad_theora->ycbcr[1].stride = krad_theora->info.frame_width / 2;
        krad_theora->ycbcr[1].width =  krad_theora->info.frame_width / 2;
        krad_theora->ycbcr[1].height =  krad_theora->info.frame_height;
        krad_theora->ycbcr[2].stride = krad_theora->info.frame_width / 2;
        krad_theora->ycbcr[2].width = krad_theora->info.frame_width / 2;
        krad_theora->ycbcr[2].height =  krad_theora->info.frame_height;

        krad_theora->ycbcr[1].data = calloc(1, ((krad_theora->info.frame_width / 2) * krad_theora->info.frame_height));
        krad_theora->ycbcr[2].data = calloc(1, ((krad_theora->info.frame_width / 2) * krad_theora->info.frame_height));

      }
      if (krad_theora->color_depth == PIX_FMT_YUV444P) {
        krad_theora->ycbcr[1].stride = krad_theora->info.frame_width;
        krad_theora->ycbcr[1].width = krad_theora->info.frame_width;
        krad_theora->ycbcr[1].height = krad_theora->info.frame_height;
        krad_theora->ycbcr[2].stride = krad_theora->info.frame_width;
        krad_theora->ycbcr[2].width = krad_theora->info.frame_width;
        krad_theora->ycbcr[2].height = krad_theora->info.frame_height;

        krad_theora->ycbcr[1].data = calloc(1, krad_theora->info.frame_width * krad_theora->info.frame_height);
        krad_theora->ycbcr[2].data = calloc(1, krad_theora->info.frame_width * krad_theora->info.frame_height);
      }
    */
    return krad_theora;

}
Exemplo n.º 14
0
	void VideoClip_Theora::_readTheoraVorbisHeaders()
	{
		ogg_packet tempOggPacket;
		//init Vorbis/Theora Layer
		//Ensure all structures get cleared out.
		memset(&this->info.OggSyncState, 0, sizeof(ogg_sync_state));
		memset(&this->info.OggPage, 0, sizeof(ogg_page));
		memset(&this->info.VorbisStreamState, 0, sizeof(ogg_stream_state));
		memset(&this->info.TheoraStreamState, 0, sizeof(ogg_stream_state));
		memset(&this->info.TheoraInfo, 0, sizeof(th_info));
		memset(&this->info.TheoraComment, 0, sizeof(th_comment));
		memset(&this->info.VorbisInfo, 0, sizeof(vorbis_info));
		memset(&this->info.VorbisDSPState, 0, sizeof(vorbis_dsp_state));
		memset(&this->info.VorbisBlock, 0, sizeof(vorbis_block));
		memset(&this->info.VorbisComment, 0, sizeof(vorbis_comment));
		// init all structures
		ogg_sync_init(&this->info.OggSyncState);
		th_comment_init(&this->info.TheoraComment);
		th_info_init(&this->info.TheoraInfo);
		vorbis_info_init(&this->info.VorbisInfo);
		vorbis_comment_init(&this->info.VorbisComment);
		// start
		ogg_stream_state oggStateTest;
		bool decodeAudio = (theoraplayer::manager->getAudioInterfaceFactory() != NULL);
		char* buffer = NULL;
		int bytesRead = 0;
		bool done = false;
		while (!done)
		{
			buffer = ogg_sync_buffer(&this->info.OggSyncState, BUFFER_SIZE);
			bytesRead = this->stream->read(buffer, BUFFER_SIZE);
			ogg_sync_wrote(&this->info.OggSyncState, bytesRead);
			if (bytesRead == 0)
			{
				break;
			}
			while (ogg_sync_pageout(&this->info.OggSyncState, &this->info.OggPage) > 0)
			{
				memset(&oggStateTest, 0, sizeof(oggStateTest));
				//is this an initial header? If not, stop
				if (ogg_page_bos(&this->info.OggPage) == 0)
				{
					//This is done blindly, because stream only accept themselves
					if (this->theoraStreams > 0)
					{
						ogg_stream_pagein(&this->info.TheoraStreamState, &this->info.OggPage);
					}
					if (this->vorbisStreams > 0)
					{
						ogg_stream_pagein(&this->info.VorbisStreamState, &this->info.OggPage);
					}
					done = true;
					break;
				}
				ogg_stream_init(&oggStateTest, ogg_page_serialno(&this->info.OggPage));
				ogg_stream_pagein(&oggStateTest, &this->info.OggPage);
				ogg_stream_packetout(&oggStateTest, &tempOggPacket);
				// identify the codec
				if (this->theoraStreams == 0 && th_decode_headerin(&this->info.TheoraInfo, &this->info.TheoraComment, &this->info.TheoraSetup, &tempOggPacket) > 0)
				{
					// This is the Theora Header
					memcpy(&this->info.TheoraStreamState, &oggStateTest, sizeof(oggStateTest));
					this->theoraStreams = 1;
				}
				else if (decodeAudio && this->vorbisStreams == 0 && vorbis_synthesis_headerin(&this->info.VorbisInfo, &this->info.VorbisComment, &tempOggPacket) >= 0)
				{
					// This is vorbis header
					memcpy(&this->info.VorbisStreamState, &oggStateTest, sizeof(oggStateTest));
					this->vorbisStreams = 1;
				}
				else // Hm, guess it's not a header we support, so erase it
				{
					ogg_stream_clear(&oggStateTest);
				}
			}
		}
		int result = 0;
		while ((this->theoraStreams > 0 && this->theoraStreams < 3) || (this->vorbisStreams && this->vorbisStreams < 3))
		{
			// Check 2nd'dary headers... Theora First
			while (this->theoraStreams > 0 && this->theoraStreams < 3 && (result = ogg_stream_packetout(&this->info.TheoraStreamState, &tempOggPacket)))
			{
				if (result < 0)
				{
					throw TheoraplayerException("Error parsing Theora stream headers!");
				}
				if (th_decode_headerin(&this->info.TheoraInfo, &this->info.TheoraComment, &this->info.TheoraSetup, &tempOggPacket) == 0)
				{
					throw TheoraplayerException("Invalid theora stream!");
				}
				++this->theoraStreams;
			} // end while looking for more theora headers
			  // look 2nd vorbis header packets
			while (this->vorbisStreams < 3 && (result = ogg_stream_packetout(&this->info.VorbisStreamState, &tempOggPacket)))
			{
				if (result < 0)
				{
					throw TheoraplayerException("Error parsing vorbis stream headers!");
				}
				if (vorbis_synthesis_headerin(&this->info.VorbisInfo, &this->info.VorbisComment, &tempOggPacket) != 0)
				{
					throw TheoraplayerException("Invalid stream!");
				}
				++this->vorbisStreams;
			} // end while looking for more vorbis headers
			  // Not finished with Headers, get some more file data
			if (ogg_sync_pageout(&this->info.OggSyncState, &this->info.OggPage) > 0)
			{
				if (this->theoraStreams > 0)
				{
					ogg_stream_pagein(&this->info.TheoraStreamState, &this->info.OggPage);
				}
				if (this->vorbisStreams > 0)
				{
					ogg_stream_pagein(&this->info.VorbisStreamState, &this->info.OggPage);
				}
			}
			else
			{
				buffer = ogg_sync_buffer(&this->info.OggSyncState, BUFFER_SIZE);
				bytesRead = this->stream->read(buffer, BUFFER_SIZE);
				ogg_sync_wrote(&this->info.OggSyncState, bytesRead);
				if (bytesRead == 0)
				{
					throw TheoraplayerException("End of file found prematurely!");
				}
			}
		} // end while looking for all headers
		  //log("Vorbis Headers: " + str(mVorbisHeaders) + " Theora Headers : " + str(mTheoraHeaders));
	}
Exemplo n.º 15
0
int main(int argc,char *argv[]){

  ogg_packet op;

  int long_option_index;
  int c;

  struct timeb start;
  struct timeb after;
  struct timeb last;
  int fps_only=0;
  int frames = 0;

  FILE *infile = stdin;
  outfile = stdout;

#ifdef _WIN32 /* We need to set stdin/stdout to binary mode on windows. */
  /* Beware the evil ifdef. We avoid these where we can, but this one we
     cannot. Don't add any more, you'll probably go to hell if you do. */
  _setmode( _fileno( stdin ), _O_BINARY );
  _setmode( _fileno( stdout ), _O_BINARY );
#endif

  /* Process option arguments. */
  while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
    switch(c){
    case 'o':
      if(strcmp(optarg,"-")!=0){
        outfile=fopen(optarg,"wb");
        if(outfile==NULL){
          fprintf(stderr,"Unable to open output file '%s'\n", optarg);
          exit(1);
        }
      }else{
        outfile=stdout;
      }
      break;

    case 'c':
      crop=1;
      break;

    case 'r':
      raw=1;
      break;

    case 'f':
      fps_only = 1;
      outfile = NULL;
      break;

    default:
      usage();
    }
  }
  if(optind<argc){
    infile=fopen(argv[optind],"rb");
    if(infile==NULL){
      fprintf(stderr,"Unable to open '%s' for extraction.\n", argv[optind]);
      exit(1);
    }
    if(++optind<argc){
      usage();
      exit(1);
    }
  }
  /*Ok, Ogg parsing.
    The idea here is we have a bitstream that is made up of Ogg pages.
    The libogg sync layer will find them for us.
    There may be pages from several logical streams interleaved; we find the
     first theora stream and ignore any others.
    Then we pass the pages for our stream to the libogg stream layer which
     assembles our original set of packets out of them.
    It's the packets that libtheora actually knows how to handle.*/

  /* start up Ogg stream synchronization layer */
  ogg_sync_init(&oy);

  /* init supporting Theora structures needed in header parsing */
  th_comment_init(&tc);
  th_info_init(&ti);

  /*Ogg file open; parse the headers.
    Theora (like Vorbis) depends on some initial header packets for decoder
     setup and initialization.
    We retrieve these first before entering the main decode loop.*/

  /* Only interested in Theora streams */
  while(!stateflag){
    int ret=buffer_data(infile,&oy);
    if(ret==0)break;
    while(ogg_sync_pageout(&oy,&og)>0){
      int got_packet;
      ogg_stream_state test;

      /* is this a mandated initial header? If not, stop parsing */
      if(!ogg_page_bos(&og)){
        /* don't leak the page; get it into the appropriate stream */
        queue_page(&og);
        stateflag=1;
        break;
      }

      ogg_stream_init(&test,ogg_page_serialno(&og));
      ogg_stream_pagein(&test,&og);
      got_packet = ogg_stream_packetpeek(&test,&op);

      /* identify the codec: try theora */
      if((got_packet==1) && !theora_p && (theora_processing_headers=
       th_decode_headerin(&ti,&tc,&ts,&op))>=0){
        /* it is theora -- save this stream state */
        memcpy(&to,&test,sizeof(test));
        theora_p=1;
        /*Advance past the successfully processed header.*/
        if(theora_processing_headers)ogg_stream_packetout(&to,NULL);
      }else{
        /* whatever it is, we don't care about it */
        ogg_stream_clear(&test);
      }
    }
    /* fall through to non-bos page parsing */
  }

  /* we're expecting more header packets. */
  while(theora_p && theora_processing_headers){
    int ret;

    /* look for further theora headers */
    while(theora_processing_headers&&(ret=ogg_stream_packetpeek(&to,&op))){
      if(ret<0)continue;
      theora_processing_headers=th_decode_headerin(&ti,&tc,&ts,&op);
      if(theora_processing_headers<0){
        fprintf(stderr,"Error parsing Theora stream headers; "
         "corrupt stream?\n");
        exit(1);
      }
      else if(theora_processing_headers>0){
        /*Advance past the successfully processed header.*/
        ogg_stream_packetout(&to,NULL);
      }
      theora_p++;
    }

    /*Stop now so we don't fail if there aren't enough pages in a short
       stream.*/
    if(!(theora_p && theora_processing_headers))break;

    /* The header pages/packets will arrive before anything else we
       care about, or the stream is not obeying spec */

    if(ogg_sync_pageout(&oy,&og)>0){
      queue_page(&og); /* demux into the appropriate stream */
    }else{
      int ret=buffer_data(infile,&oy); /* someone needs more data */
      if(ret==0){
        fprintf(stderr,"End of file while searching for codec headers.\n");
        exit(1);
      }
    }
  }

  /* and now we have it all.  initialize decoders */
  if(theora_p){
    dump_comments(&tc);
    td=th_decode_alloc(&ti,ts);
    fprintf(stderr,"Ogg logical stream %lx is Theora %dx%d %.02f fps video\n"
     "Encoded frame content is %dx%d with %dx%d offset\n",
     to.serialno,ti.frame_width,ti.frame_height,
     (double)ti.fps_numerator/ti.fps_denominator,
     ti.pic_width,ti.pic_height,ti.pic_x,ti.pic_y);

    /*{
      int arg = 0xffff;
      th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_MBMODE,&arg,sizeof(arg));
      th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_MV,&arg,sizeof(arg));
      th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_QI,&arg,sizeof(arg));
      arg=10;
      th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_BITS,&arg,sizeof(arg));
    }*/
  }else{
    /* tear down the partial theora setup */
    th_info_clear(&ti);
    th_comment_clear(&tc);
  }
  /*Either way, we're done with the codec setup data.*/
  th_setup_free(ts);

  /* open video */
  if(theora_p)open_video();

  if(!raw && outfile){
    static const char *CHROMA_TYPES[4]={"420jpeg",NULL,"422jpeg","444"};
    int width;
    int height;
    if(ti.pixel_fmt>=4||ti.pixel_fmt==TH_PF_RSVD){
      fprintf(stderr,"Unknown pixel format: %i\n",ti.pixel_fmt);
      exit(1);
    }
    if(crop){
      int hdec;
      int vdec;
      hdec=!(ti.pixel_fmt&1);
      vdec=!(ti.pixel_fmt&2);
      if((ti.pic_x&hdec)||(ti.pic_width&hdec)
       ||(ti.pic_y&vdec)||(ti.pic_height&vdec)){
        fprintf(stderr,
         "Error: Cropped images with odd offsets/sizes and chroma subsampling\n"
         "cannot be output to YUV4MPEG2. Remove the --crop flag or add the\n"
         "--raw flag.\n");
        exit(1);
      }
      width=ti.pic_width;
      height=ti.pic_height;
    }
    else{
      width=ti.frame_width;
      height=ti.frame_height;
    }
    fprintf(outfile,"YUV4MPEG2 C%s W%d H%d F%d:%d I%c A%d:%d\n",
     CHROMA_TYPES[ti.pixel_fmt],width,height,
     ti.fps_numerator,ti.fps_denominator,'p',
     ti.aspect_numerator,ti.aspect_denominator);
  }

  /* install signal handler */
  signal (SIGINT, sigint_handler);

  /*Finally the main decode loop.

    It's one Theora packet per frame, so this is pretty straightforward if
     we're not trying to maintain sync with other multiplexed streams.

    The videobuf_ready flag is used to maintain the input buffer in the libogg
     stream state.
    If there's no output frame available at the end of the decode step, we must
     need more input data.
    We could simplify this by just using the return code on
     ogg_page_packetout(), but the flag system extends easily to the case where
     you care about more than one multiplexed stream (like with audio
     playback).
    In that case, just maintain a flag for each decoder you care about, and
     pull data when any one of them stalls.

    videobuf_time holds the presentation time of the currently buffered video
     frame.
    We ignore this value.*/

  stateflag=0; /* playback has not begun */
  /* queue any remaining pages from data we buffered but that did not
      contain headers */
  while(ogg_sync_pageout(&oy,&og)>0){
    queue_page(&og);
  }

  if(fps_only){
    ftime(&start);
    ftime(&last);
  }

  while(!got_sigint){

    while(theora_p && !videobuf_ready){
      /* theora is one in, one out... */
      if(ogg_stream_packetout(&to,&op)>0){

        if(th_decode_packetin(td,&op,&videobuf_granulepos)>=0){
          videobuf_time=th_granule_time(td,videobuf_granulepos);
          videobuf_ready=1;
          frames++;
          if(fps_only)
            ftime(&after);
        }

      }else
        break;
    }

    if(fps_only && (videobuf_ready || fps_only==2)){
      long ms =
        after.time*1000.+after.millitm-
        (last.time*1000.+last.millitm);

      if(ms>500 || fps_only==1 ||
         (feof(infile) && !videobuf_ready)){
        float file_fps = (float)ti.fps_numerator/ti.fps_denominator;
        fps_only=2;

        ms = after.time*1000.+after.millitm-
          (start.time*1000.+start.millitm);

        fprintf(stderr,"\rframe:%d rate:%.2fx           ",
                frames,
                frames*1000./(ms*file_fps));
        memcpy(&last,&after,sizeof(last));
      }
    }

    if(!videobuf_ready && feof(infile))break;

    if(!videobuf_ready){
      /* no data yet for somebody.  Grab another page */
      buffer_data(infile,&oy);
      while(ogg_sync_pageout(&oy,&og)>0){
        queue_page(&og);
      }
    }
    /* dumpvideo frame, and get new one */
    else if(outfile)video_write();

    videobuf_ready=0;
  }

  /* end of decoder loop -- close everything */

  if(theora_p){
    ogg_stream_clear(&to);
    th_decode_free(td);
    th_comment_clear(&tc);
    th_info_clear(&ti);
  }
  ogg_sync_clear(&oy);

  if(infile && infile!=stdin)fclose(infile);
  if(outfile && outfile!=stdout)fclose(outfile);

  fprintf(stderr, "\n\n%d frames\n", frames);
  fprintf(stderr, "\nDone.\n");

  return(0);

}
Exemplo n.º 16
0
void theora_comment_init(theora_comment *_tc){
  th_comment_init((th_comment *)_tc);
}
Exemplo n.º 17
0
static GstFlowReturn
theora_enc_handle_frame (GstVideoEncoder * benc, GstVideoCodecFrame * frame)
{
    GstTheoraEnc *enc;
    ogg_packet op;
    GstClockTime timestamp, running_time;
    GstFlowReturn ret;
    gboolean force_keyframe;

    enc = GST_THEORA_ENC (benc);

    /* we keep track of two timelines.
     * - The timestamps from the incomming buffers, which we copy to the outgoing
     *   encoded buffers as-is. We need to do this as we simply forward the
     *   newsegment events.
     * - The running_time of the buffers, which we use to construct the granulepos
     *   in the packets.
     */
    timestamp = frame->pts;

    /* incoming buffers are clipped, so this should be positive */
    running_time =
        gst_segment_to_running_time (&GST_VIDEO_ENCODER_INPUT_SEGMENT (enc),
                                     GST_FORMAT_TIME, timestamp);
    g_return_val_if_fail (running_time >= 0 || timestamp < 0, GST_FLOW_ERROR);

    GST_OBJECT_LOCK (enc);
    if (enc->bitrate_changed) {
        long int bitrate = enc->video_bitrate;

        th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
                       sizeof (long int));
        enc->bitrate_changed = FALSE;
    }

    if (enc->quality_changed) {
        long int quality = enc->video_quality;

        th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
                       sizeof (long int));
        enc->quality_changed = FALSE;
    }

    /* see if we need to schedule a keyframe */
    force_keyframe = GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame);
    GST_OBJECT_UNLOCK (enc);

    if (enc->packetno == 0) {
        /* no packets written yet, setup headers */
        GstCaps *caps;
        GstBuffer *buf;
        GList *buffers = NULL;
        int result;
        GstVideoCodecState *state;

        enc->granulepos_offset = 0;
        enc->timestamp_offset = 0;

        GST_DEBUG_OBJECT (enc, "output headers");
        /* Theora streams begin with three 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.  The
           third header holds the bitstream codebook.  We merely need to
           make the headers, then pass them to libtheora one at a time;
           libtheora handles the additional Ogg bitstream constraints */

        /* create the remaining theora headers */
        th_comment_clear (&enc->comment);
        th_comment_init (&enc->comment);

        while ((result =
                    th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
            buf = theora_enc_buffer_from_header_packet (enc, &op);
            buffers = g_list_prepend (buffers, buf);
        }
        if (result < 0) {
            g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
            g_list_free (buffers);
            goto encoder_disabled;
        }

        buffers = g_list_reverse (buffers);

        /* mark buffers and put on caps */
        caps = gst_caps_new_empty_simple ("video/x-theora");
        caps = theora_set_header_on_caps (caps, buffers);
        state = gst_video_encoder_set_output_state (benc, caps, enc->input_state);

        GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, state->caps);

        gst_video_codec_state_unref (state);

        gst_video_encoder_negotiate (GST_VIDEO_ENCODER (enc));

        gst_video_encoder_set_headers (benc, buffers);

        theora_enc_reset_ts (enc, running_time, frame->presentation_frame_number);
    }

    {
        th_ycbcr_buffer ycbcr;
        gint res;
        GstVideoFrame vframe;

        if (force_keyframe) {
            theora_enc_reset (enc);
            theora_enc_reset_ts (enc, running_time, frame->presentation_frame_number);
        }

        if (enc->multipass_cache_fd
                && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
            if (!theora_enc_read_multipass_cache (enc)) {
                ret = GST_FLOW_ERROR;
                goto multipass_read_failed;
            }
        }

        gst_video_frame_map (&vframe, &enc->input_state->info, frame->input_buffer,
                             GST_MAP_READ);
        theora_enc_init_buffer (ycbcr, &vframe);

        res = th_encode_ycbcr_in (enc->encoder, ycbcr);
        gst_video_frame_unmap (&vframe);

        /* none of the failure cases can happen here */
        g_assert (res == 0);

        if (enc->multipass_cache_fd
                && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
            if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
                ret = GST_FLOW_ERROR;
                goto multipass_write_failed;
            }
        }

        ret = GST_FLOW_OK;
        while (th_encode_packetout (enc->encoder, 0, &op)) {
            ret = theora_push_packet (enc, &op);
            if (ret != GST_FLOW_OK)
                goto beach;
        }
    }

beach:
    gst_video_codec_frame_unref (frame);
    return ret;

    /* ERRORS */
multipass_read_failed:
    {
        gst_video_codec_frame_unref (frame);
        return ret;
    }
multipass_write_failed:
    {
        gst_video_codec_frame_unref (frame);
        return ret;
    }
encoder_disabled:
    {
        gst_video_codec_frame_unref (frame);
        GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
                           ("libtheora has been compiled with the encoder disabled"));
        return GST_FLOW_ERROR;
    }
}
Exemplo n.º 18
0
int main(int argc,char *const *argv){

  int pp_level_max;
  int pp_level;
  int pp_inc;
  int i,j;
  ogg_packet op;

  FILE *infile = stdin;

  int frames = 0;
  int dropped = 0;

#ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
  /* Beware the evil ifdef. We avoid these where we can, but this one we
     cannot. Don't add any more, you'll probably go to hell if you do. */
  _setmode( _fileno( stdin ), _O_BINARY );
#endif

  /* open the input file if any */
  if(argc==2){
    infile=fopen(argv[1],"rb");
    if(infile==NULL){
      fprintf(stderr,"Unable to open '%s' for playback.\n", argv[1]);
      exit(1);
    }
  }
  if(argc>2){
      usage();
      exit(1);
  }

  /* start up Ogg stream synchronization layer */
  ogg_sync_init(&oy);

  /* init supporting Vorbis structures needed in header parsing */
  vorbis_info_init(&vi);
  vorbis_comment_init(&vc);

  /* init supporting Theora structures needed in header parsing */
  th_comment_init(&tc);
  th_info_init(&ti);

  /* Ogg file open; parse the headers */
  /* Only interested in Vorbis/Theora streams */
  while(!stateflag){
    int ret=buffer_data(infile,&oy);
    if(ret==0)break;
    while(ogg_sync_pageout(&oy,&og)>0){
      ogg_stream_state test;

      /* is this a mandated initial header? If not, stop parsing */
      if(!ogg_page_bos(&og)){
        /* don't leak the page; get it into the appropriate stream */
        queue_page(&og);
        stateflag=1;
        break;
      }

      ogg_stream_init(&test,ogg_page_serialno(&og));
      ogg_stream_pagein(&test,&og);
      ogg_stream_packetout(&test,&op);


      /* identify the codec: try theora */
      if(!theora_p && th_decode_headerin(&ti,&tc,&ts,&op)>=0){
        /* it is theora */
        memcpy(&to,&test,sizeof(test));
        theora_p=1;
      }else if(!vorbis_p && vorbis_synthesis_headerin(&vi,&vc,&op)>=0){
        /* it is vorbis */
        memcpy(&vo,&test,sizeof(test));
        vorbis_p=1;
      }else{
        /* whatever it is, we don't care about it */
        ogg_stream_clear(&test);
      }
    }
    /* fall through to non-bos page parsing */
  }

  /* we're expecting more header packets. */
  while((theora_p && theora_p<3) || (vorbis_p && vorbis_p<3)){
    int ret;

    /* look for further theora headers */
    while(theora_p && (theora_p<3) && (ret=ogg_stream_packetout(&to,&op))){
      if(ret<0){
        fprintf(stderr,"Error parsing Theora stream headers; "
         "corrupt stream?\n");
        exit(1);
      }
      if(!th_decode_headerin(&ti,&tc,&ts,&op)){
        fprintf(stderr,"Error parsing Theora stream headers; "
         "corrupt stream?\n");
        exit(1);
      }
      theora_p++;
    }

    /* look for more vorbis header packets */
    while(vorbis_p && (vorbis_p<3) && (ret=ogg_stream_packetout(&vo,&op))){
      if(ret<0){
        fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n");
        exit(1);
      }
      if(vorbis_synthesis_headerin(&vi,&vc,&op)){
        fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n");
        exit(1);
      }
      vorbis_p++;
      if(vorbis_p==3)break;
    }

    /* The header pages/packets will arrive before anything else we
       care about, or the stream is not obeying spec */

    if(ogg_sync_pageout(&oy,&og)>0){
      queue_page(&og); /* demux into the appropriate stream */
    }else{
      int ret=buffer_data(infile,&oy); /* someone needs more data */
      if(ret==0){
        fprintf(stderr,"End of file while searching for codec headers.\n");
        exit(1);
      }
    }
  }

  /* and now we have it all.  initialize decoders */
  if(theora_p){
    td=th_decode_alloc(&ti,ts);
    printf("Ogg logical stream %lx is Theora %dx%d %.02f fps",
           to.serialno,ti.pic_width,ti.pic_height,
           (double)ti.fps_numerator/ti.fps_denominator);
    px_fmt=ti.pixel_fmt;
    switch(ti.pixel_fmt){
      case TH_PF_420: printf(" 4:2:0 video\n"); break;
      case TH_PF_422: printf(" 4:2:2 video\n"); break;
      case TH_PF_444: printf(" 4:4:4 video\n"); break;
      case TH_PF_RSVD:
      default:
       printf(" video\n  (UNKNOWN Chroma sampling!)\n");
       break;
    }
    if(ti.pic_width!=ti.frame_width || ti.pic_height!=ti.frame_height)
      printf("  Frame content is %dx%d with offset (%d,%d).\n",
           ti.frame_width, ti.frame_height, ti.pic_x, ti.pic_y);
    report_colorspace(&ti);
    dump_comments(&tc);
    th_decode_ctl(td,TH_DECCTL_GET_PPLEVEL_MAX,&pp_level_max,
     sizeof(pp_level_max));
    pp_level=pp_level_max;
    th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level,sizeof(pp_level));
    pp_inc=0;

    /*{
      int arg = 0xffff;
      th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_MBMODE,&arg,sizeof(arg));
      th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_MV,&arg,sizeof(arg));
      th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_QI,&arg,sizeof(arg));
      arg=10;
      th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_BITS,&arg,sizeof(arg));
    }*/
  }else{
    /* tear down the partial theora setup */
    th_info_clear(&ti);
    th_comment_clear(&tc);
  }
  
  th_setup_free(ts);
  
  if(vorbis_p){
    vorbis_synthesis_init(&vd,&vi);
    vorbis_block_init(&vd,&vb);
    fprintf(stderr,"Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.\n",
            vo.serialno,vi.channels,vi.rate);
  }else{
    /* tear down the partial vorbis setup */
    vorbis_info_clear(&vi);
    vorbis_comment_clear(&vc);
  }

  /* open audio */
  if(vorbis_p)open_audio();

  /* open video */
  if(theora_p)open_video();

  /* install signal handler as SDL clobbered the default */
  signal (SIGINT, sigint_handler);

  /* on to the main decode loop.  We assume in this example that audio
     and video start roughly together, and don't begin playback until
     we have a start frame for both.  This is not necessarily a valid
     assumption in Ogg A/V streams! It will always be true of the
     example_encoder (and most streams) though. */

  stateflag=0; /* playback has not begun */
  while(!got_sigint){

    /* we want a video and audio frame ready to go at all times.  If
       we have to buffer incoming, buffer the compressed data (ie, let
       ogg do the buffering) */
    while(vorbis_p && !audiobuf_ready){
      int ret;
      float **pcm;

      /* if there's pending, decoded audio, grab it */
      if((ret=vorbis_synthesis_pcmout(&vd,&pcm))>0){
        int count=audiobuf_fill/2;
        int maxsamples=(audiofd_fragsize-audiobuf_fill)/2/vi.channels;
        for(i=0;i<ret && i<maxsamples;i++)
          for(j=0;j<vi.channels;j++){
            int val=rint(pcm[j][i]*32767.f);
            if(val>32767)val=32767;
            if(val<-32768)val=-32768;
            audiobuf[count++]=val;
          }
        vorbis_synthesis_read(&vd,i);
        audiobuf_fill+=i*vi.channels*2;
        if(audiobuf_fill==audiofd_fragsize)audiobuf_ready=1;
        if(vd.granulepos>=0)
          audiobuf_granulepos=vd.granulepos-ret+i;
        else
          audiobuf_granulepos+=i;

      }else{

        /* no pending audio; is there a pending packet to decode? */
        if(ogg_stream_packetout(&vo,&op)>0){
          if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
            vorbis_synthesis_blockin(&vd,&vb);
        }else   /* we need more data; break out to suck in another page */
          break;
      }
    }

    while(theora_p && !videobuf_ready){
      /* theora is one in, one out... */
      if(ogg_stream_packetout(&to,&op)>0){

        if(pp_inc){
          pp_level+=pp_inc;
          th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level,
           sizeof(pp_level));
          pp_inc=0;
        }
        /*HACK: This should be set after a seek or a gap, but we might not have
           a granulepos for the first packet (we only have them for the last
           packet on a page), so we just set it as often as we get it.
          To do this right, we should back-track from the last packet on the
           page and compute the correct granulepos for the first packet after
           a seek or a gap.*/
        if(op.granulepos>=0){
          th_decode_ctl(td,TH_DECCTL_SET_GRANPOS,&op.granulepos,
           sizeof(op.granulepos));
        }
        if(th_decode_packetin(td,&op,&videobuf_granulepos)==0){
          videobuf_time=th_granule_time(td,videobuf_granulepos);
          frames++;

          /* is it already too old to be useful?  This is only actually
             useful cosmetically after a SIGSTOP.  Note that we have to
             decode the frame even if we don't show it (for now) due to
             keyframing.  Soon enough libtheora will be able to deal
             with non-keyframe seeks.  */

          if(videobuf_time>=get_time())
            videobuf_ready=1;
          else{
            /*If we are too slow, reduce the pp level.*/
            pp_inc=pp_level>0?-1:0;
            dropped++;
          }
        }

      }else
        break;
    }

    if(!videobuf_ready && !audiobuf_ready && feof(infile))break;

    if(!videobuf_ready || !audiobuf_ready){
      /* no data yet for somebody.  Grab another page */
      buffer_data(infile,&oy);
      while(ogg_sync_pageout(&oy,&og)>0){
        queue_page(&og);
      }
    }

    /* If playback has begun, top audio buffer off immediately. */
    if(stateflag) audio_write_nonblocking();

    /* are we at or past time for this video frame? */
    if(stateflag && videobuf_ready && videobuf_time<=get_time()){
      video_write();
      videobuf_ready=0;
    }

    if(stateflag &&
       (audiobuf_ready || !vorbis_p) &&
       (videobuf_ready || !theora_p) &&
       !got_sigint){
      /* we have an audio frame ready (which means the audio buffer is
         full), it's not time to play video, so wait until one of the
         audio buffer is ready or it's near time to play video */

      /* set up select wait on the audiobuffer and a timeout for video */
      struct timeval timeout;
      fd_set writefs;
      fd_set empty;
      int n=0;

      FD_ZERO(&writefs);
      FD_ZERO(&empty);
      if(audiofd>=0){
        FD_SET(audiofd,&writefs);
        n=audiofd+1;
      }

      if(theora_p){
        double tdiff;
        long milliseconds;
        tdiff=videobuf_time-get_time();
        /*If we have lots of extra time, increase the post-processing level.*/
        if(tdiff>ti.fps_denominator*0.25/ti.fps_numerator){
          pp_inc=pp_level<pp_level_max?1:0;
        }
        else if(tdiff<ti.fps_denominator*0.05/ti.fps_numerator){
          pp_inc=pp_level>0?-1:0;
        }
        milliseconds=tdiff*1000-5;
        if(milliseconds>500)milliseconds=500;
        if(milliseconds>0){
          timeout.tv_sec=milliseconds/1000;
          timeout.tv_usec=(milliseconds%1000)*1000;

          n=select(n,&empty,&writefs,&empty,&timeout);
          if(n)audio_calibrate_timer(0);
        }
      }else{
        select(n,&empty,&writefs,&empty,NULL);
      }
    }

    /* if our buffers either don't exist or are ready to go,
       we can begin playback */
    if((!theora_p || videobuf_ready) &&
       (!vorbis_p || audiobuf_ready))stateflag=1;
    /* same if we've run out of input */
    if(feof(infile))stateflag=1;

  }

  /* tear it all down */

  audio_close();
  SDL_Quit();

  if(vorbis_p){
    ogg_stream_clear(&vo);
    vorbis_block_clear(&vb);
    vorbis_dsp_clear(&vd);
    vorbis_comment_clear(&vc);
    vorbis_info_clear(&vi);
  }
  if(theora_p){
    ogg_stream_clear(&to);
    th_decode_free(td);
    th_comment_clear(&tc);
    th_info_clear(&ti);
  }
  ogg_sync_clear(&oy);

  if(infile && infile!=stdin)fclose(infile);

  fprintf(stderr,
          "\r                                                             \r");
  fprintf(stderr, "%d frames", frames);
  if (dropped) fprintf(stderr, " (%d dropped)", dropped);
  fprintf(stderr, "\n");
  fprintf(stderr, "\nDone.\n");

  return(0);

}
Exemplo n.º 19
0
static BGBBTJ_VidCodecCTX *theo_begin_compress(int fcc,
	BGBBTJ_BMPInfoHeader *in, BGBBTJ_BMPInfoHeader *out)
{
	byte tbuf[16384];
	ogg_packet op;
	BGBBTJ_VidCodecCTX *ctx;
	vfw_ctxinfo *info;
	byte *ct;
	int err, sz, xs, ys, xs1, ys1, px, py;

	if((fcc!=RIFF_TAG_THEO) && (fcc!=RIFF_TAG_theo) &&
			(fcc!=RIFF_TAG_ther))
		return(NULL);

	ctx=BGBBTJ_VidCodecCTX_New();
	info=gcalloc(sizeof(vfw_ctxinfo));
	ctx->data=info;

	info->ihead=gcalloc(sizeof(BGBBTJ_BMPInfoHeader));
	memset(info->ihead, 0, sizeof(BGBBTJ_BMPInfoHeader));
	info->ihead->biSize		= sizeof(BGBBTJ_BMPInfoHeader);
	info->ihead->biWidth		= in->biWidth;
	info->ihead->biHeight		= in->biHeight;
	info->ihead->biPlanes		= in->biPlanes;
	info->ihead->biBitCount		= in->biBitCount;
	info->ihead->biCompression	= in->biCompression;
	info->ihead->biSizeImage	=
		in->biWidth*in->biHeight*in->biBitCount/8;

//	out->biCompression=RIFF_TAG_ther;
	out->biCompression=RIFF_TAG_theo;

	info->ohead=gcalloc(sizeof(BGBBTJ_BMPInfoHeader));
	memset(info->ohead, 0, sizeof(BGBBTJ_BMPInfoHeader));
	info->ohead->biSize		= sizeof(BGBBTJ_BMPInfoHeader);
	info->ohead->biWidth		= out->biWidth;
//	info->ohead->biHeight		= -out->biHeight;
	info->ohead->biHeight		= out->biHeight;
	info->ohead->biPlanes		= out->biPlanes;
	info->ohead->biBitCount		= out->biBitCount;
	info->ohead->biCompression	= out->biCompression;
	info->ihead->biSizeImage	=
		out->biWidth*out->biHeight*out->biBitCount/8;

//	info->buffer=malloc(out->width*out->height*out->bpp/8);

	theora_info_init(&(info->ti));
//	if(err<0)printf("theo_begin_compress: A Err=%d\n");

	xs=(out->biWidth+15)&(~15);
	ys=(out->biHeight+15)&(~15);
	xs1=xs>>1;
	ys1=ys>>1;

    px=((xs-out->biWidth)>>1)&(~1);
    py=((ys-out->biHeight)>>1)&(~1);

	info->ti.width = out->biWidth;
	info->ti.height = out->biHeight;
	info->ti.frame_width = xs;
	info->ti.frame_height = ys;
    info->ti.offset_x=px;
	info->ti.offset_y=py;
//	info->ti.pixel_fmt=TH_PF_420;
	info->ti.pixelformat=TH_PF_420;
//	info->ti.quality=56;
	info->ti.quality=63;
	info->ti.colorspace=TH_CS_UNSPECIFIED;

	info->ti.fps_numerator=24;
	info->ti.fps_denominator=1;
	info->ti.aspect_numerator=1;
	info->ti.aspect_denominator=1;

	th_info_init(&(info->thi));
//	if(err<0)printf("theo_begin_compress: B Err=%d\n");

	info->thi.pic_width = out->biWidth;
	info->thi.pic_height = out->biHeight;
	info->thi.frame_width = xs;
	info->thi.frame_height = ys;
    info->thi.pic_x=px;
	info->thi.pic_y=py;
	info->thi.fps_numerator=24;
	info->thi.fps_denominator=1;

	info->thi.aspect_numerator=1;
	info->thi.aspect_denominator=1;
	
	info->thi.colorspace=TH_CS_UNSPECIFIED;
	info->thi.pixel_fmt=TH_PF_420;
//	info->thi.pixelformat=TH_PF_420;
//	info->thi.quality=48;
	info->thi.quality=63;

	if(theora_encode_init(&(info->th), &(info->ti)) != OC_DISABLED)
		{ theora_clear(&(info->th)); }

	info->td=th_encode_alloc(&(info->thi));
	th_info_clear(&(info->thi));
//	if(err<0)printf("theo_begin_compress: C Err=%d\n");

	th_comment_init(&(info->tc));
//	if(err<0)printf("theo_begin_compress: D Err=%d\n");

	ct=tbuf;
	
    err=th_encode_flushheader(info->td, &(info->tc), &op);
	if(err<0)printf("theo_begin_compress: E Err=%d\n");

	ct[0]=(op.bytes>>8)&255;
	ct[1]=op.bytes&255;
	ct+=2;

    memcpy(ct, op.packet, op.bytes);
    ct+=op.bytes;

    while(1)
    {
		err=th_encode_flushheader(info->td, &(info->tc), &op);
		if(err<=0)break;

		ct[0]=(op.bytes>>8)&255;
		ct[1]=op.bytes&255;
		ct+=2;

		memcpy(ct, op.packet, op.bytes);
		ct+=op.bytes;
    }

	if(err<0)printf("theo_begin_compress: F Err=%d\n");

	sz=ct-tbuf;
	ctx->vidStrd=gcalloc(sz);
	ctx->sz_vidStrd=sz;
	memcpy(ctx->vidStrd, tbuf, sz);

	info->ycbbuf[0].width=xs;
	info->ycbbuf[0].height=ys;
	info->ycbbuf[0].stride=xs;
	info->ycbbuf[0].data=malloc(xs*ys);

	info->ycbbuf[1].width=xs1;
	info->ycbbuf[1].height=ys1;
	info->ycbbuf[1].stride=xs1;
	info->ycbbuf[1].data=malloc(xs1*ys1);

	info->ycbbuf[2].width=xs1;
	info->ycbbuf[2].height=ys1;
	info->ycbbuf[2].stride=xs1;
	info->ycbbuf[2].data=malloc(xs1*ys1);

	ctx->compress_frame=&theo_compress_frame;

	return(ctx);
}
Exemplo n.º 20
0
static GstStateChangeReturn
theora_enc_change_state (GstElement * element, GstStateChange transition)
{
  GstTheoraEnc *enc;
  GstStateChangeReturn ret;

  enc = GST_THEORA_ENC (element);

  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
      GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
      th_info_init (&enc->info);
      th_comment_init (&enc->comment);
      enc->packetno = 0;
      enc->force_keyframe = FALSE;

      if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
        GError *err = NULL;

        if (!enc->multipass_cache_file) {
          ret = GST_STATE_CHANGE_FAILURE;
          GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
          return ret;
        }
        enc->multipass_cache_fd =
            g_io_channel_new_file (enc->multipass_cache_file,
            (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"),
            &err);

        if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
          enc->multipass_cache_adapter = gst_adapter_new ();

        if (!enc->multipass_cache_fd) {
          ret = GST_STATE_CHANGE_FAILURE;
          GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
              ("Failed to open multipass cache file: %s", err->message));
          g_error_free (err);
          return ret;
        }

        g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
      }
      break;
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
      break;
    default:
      break;
  }

  ret = parent_class->change_state (element, transition);

  switch (transition) {
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
      break;
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
      if (enc->encoder) {
        th_encode_free (enc->encoder);
        enc->encoder = NULL;
      }
      th_comment_clear (&enc->comment);
      th_info_clear (&enc->info);

      theora_enc_clear (enc);
      enc->initialised = FALSE;
      break;
    case GST_STATE_CHANGE_READY_TO_NULL:
      break;
    default:
      break;
  }

  return ret;
}
Exemplo n.º 21
0
static GstFlowReturn
theora_enc_chain (GstPad * pad, GstBuffer * buffer)
{
  GstTheoraEnc *enc;
  ogg_packet op;
  GstClockTime timestamp, duration, running_time;
  GstFlowReturn ret;
  gboolean force_keyframe;

  enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));

  /* we keep track of two timelines.
   * - The timestamps from the incomming buffers, which we copy to the outgoing
   *   encoded buffers as-is. We need to do this as we simply forward the
   *   newsegment events.
   * - The running_time of the buffers, which we use to construct the granulepos
   *   in the packets.
   */
  timestamp = GST_BUFFER_TIMESTAMP (buffer);
  duration = GST_BUFFER_DURATION (buffer);

  running_time =
      gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
  if ((gint64) running_time < 0) {
    GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
    gst_buffer_unref (buffer);
    return GST_FLOW_OK;
  }

  GST_OBJECT_LOCK (enc);
  if (enc->bitrate_changed) {
    long int bitrate = enc->video_bitrate;

    th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
        sizeof (long int));
    enc->bitrate_changed = FALSE;
  }

  if (enc->quality_changed) {
    long int quality = enc->video_quality;

    th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
        sizeof (long int));
    enc->quality_changed = FALSE;
  }

  /* see if we need to schedule a keyframe */
  force_keyframe = enc->force_keyframe;
  enc->force_keyframe = FALSE;
  GST_OBJECT_UNLOCK (enc);

  if (force_keyframe) {
    GstClockTime stream_time;
    GstStructure *s;

    stream_time = gst_segment_to_stream_time (&enc->segment,
        GST_FORMAT_TIME, timestamp);

    s = gst_structure_new ("GstForceKeyUnit",
        "timestamp", G_TYPE_UINT64, timestamp,
        "stream-time", G_TYPE_UINT64, stream_time,
        "running-time", G_TYPE_UINT64, running_time, NULL);

    theora_enc_force_keyframe (enc);

    gst_pad_push_event (enc->srcpad,
        gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
  }

  /* make sure we copy the discont flag to the next outgoing buffer when it's
   * set on the incomming buffer */
  if (GST_BUFFER_IS_DISCONT (buffer)) {
    enc->next_discont = TRUE;
  }

  if (enc->packetno == 0) {
    /* no packets written yet, setup headers */
    GstCaps *caps;
    GstBuffer *buf;
    GSList *buffers = NULL;
    int result;

    enc->granulepos_offset = 0;
    enc->timestamp_offset = 0;

    GST_DEBUG_OBJECT (enc, "output headers");
    /* Theora streams begin with three 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.  The
       third header holds the bitstream codebook.  We merely need to
       make the headers, then pass them to libtheora one at a time;
       libtheora handles the additional Ogg bitstream constraints */

    /* create the remaining theora headers */
    th_comment_clear (&enc->comment);
    th_comment_init (&enc->comment);

    while ((result =
            th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
      ret =
          theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
          GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
      if (ret != GST_FLOW_OK) {
        goto header_buffer_alloc;
      }
      buffers = g_slist_prepend (buffers, buf);
    }
    if (result < 0) {
      g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
      g_slist_free (buffers);
      goto encoder_disabled;
    }

    buffers = g_slist_reverse (buffers);

    /* mark buffers and put on caps */
    caps = gst_pad_get_caps (enc->srcpad);
    caps = theora_set_header_on_caps (caps, buffers);
    GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
    gst_pad_set_caps (enc->srcpad, caps);

    g_slist_foreach (buffers, (GFunc) gst_buffer_set_caps, caps);

    gst_caps_unref (caps);

    /* push out the header buffers */
    while (buffers) {
      buf = buffers->data;
      buffers = g_slist_delete_link (buffers, buffers);
      if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
        g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
        g_slist_free (buffers);
        goto header_push;
      }
    }

    enc->granulepos_offset =
        gst_util_uint64_scale (running_time, enc->fps_n,
        GST_SECOND * enc->fps_d);
    enc->timestamp_offset = running_time;
    enc->next_ts = 0;
  }

  {
    th_ycbcr_buffer ycbcr;
    gint res;

    theora_enc_init_buffer (ycbcr, &enc->info, GST_BUFFER_DATA (buffer));

    if (theora_enc_is_discontinuous (enc, running_time, duration)) {
      theora_enc_reset (enc);
      enc->granulepos_offset =
          gst_util_uint64_scale (running_time, enc->fps_n,
          GST_SECOND * enc->fps_d);
      enc->timestamp_offset = running_time;
      enc->next_ts = 0;
      enc->next_discont = TRUE;
    }

    if (enc->multipass_cache_fd
        && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
      if (!theora_enc_read_multipass_cache (enc)) {
        ret = GST_FLOW_ERROR;
        goto multipass_read_failed;
      }
    }

    res = th_encode_ycbcr_in (enc->encoder, ycbcr);
    /* none of the failure cases can happen here */
    g_assert (res == 0);

    if (enc->multipass_cache_fd
        && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
      if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
        ret = GST_FLOW_ERROR;
        goto multipass_write_failed;
      }
    }

    ret = GST_FLOW_OK;
    while (th_encode_packetout (enc->encoder, 0, &op)) {
      GstClockTime next_time;

      next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;

      ret =
          theora_push_packet (enc, &op, timestamp, enc->next_ts,
          next_time - enc->next_ts);

      enc->next_ts = next_time;
      if (ret != GST_FLOW_OK)
        goto data_push;
    }
    gst_buffer_unref (buffer);
  }

  return ret;

  /* ERRORS */
multipass_read_failed:
  {
    gst_buffer_unref (buffer);
    return ret;
  }
multipass_write_failed:
  {
    gst_buffer_unref (buffer);
    return ret;
  }
header_buffer_alloc:
  {
    gst_buffer_unref (buffer);
    return ret;
  }
header_push:
  {
    gst_buffer_unref (buffer);
    return ret;
  }
data_push:
  {
    gst_buffer_unref (buffer);
    return ret;
  }
encoder_disabled:
  {
    GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
        ("libtheora has been compiled with the encoder disabled"));
    gst_buffer_unref (buffer);
    return GST_FLOW_ERROR;
  }
}
Exemplo n.º 22
0
bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) {
	close();

	_endOfAudio = false;
	_endOfVideo = false;
	_fileStream = stream;

	// start up Ogg stream synchronization layer
	ogg_sync_init(&_oggSync);

	// init supporting Vorbis structures needed in header parsing
	vorbis_info_init(&_vorbisInfo);
	vorbis_comment_init(&_vorbisComment);

	// init supporting Theora structures needed in header parsing
	th_comment_init(&_theoraComment);
	th_info_init(&_theoraInfo);

	// Ogg file open; parse the headers
	// Only interested in Vorbis/Theora streams
	bool foundHeader = false;
	while (!foundHeader) {
		int ret = bufferData();

		if (ret == 0)
			break;

		while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) {
			ogg_stream_state test;

			// is this a mandated initial header? If not, stop parsing
			if (!ogg_page_bos(&_oggPage)) {
				// don't leak the page; get it into the appropriate stream
				queuePage(&_oggPage);
				foundHeader = true;
				break;
			}

			ogg_stream_init(&test, ogg_page_serialno(&_oggPage));
			ogg_stream_pagein(&test, &_oggPage);
			ogg_stream_packetout(&test, &_oggPacket);

			// identify the codec: try theora
			if (!_theoraPacket && th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket) >= 0) {
				// it is theora
				memcpy(&_theoraOut, &test, sizeof(test));
				_theoraPacket = 1;
			} else if (!_vorbisPacket && vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket) >= 0) {
				// it is vorbis
				memcpy(&_vorbisOut, &test, sizeof(test));
				_vorbisPacket = 1;
			} else {
				// whatever it is, we don't care about it
				ogg_stream_clear(&test);
			}
		}
		// fall through to non-bos page parsing
	}

	// we're expecting more header packets.
	while ((_theoraPacket && _theoraPacket < 3) || (_vorbisPacket && _vorbisPacket < 3)) {
		int ret;

		// look for further theora headers
		while (_theoraPacket && (_theoraPacket < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) {
			if (ret < 0)
				error("Error parsing Theora stream headers; corrupt stream?");

			if (!th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket))
				error("Error parsing Theora stream headers; corrupt stream?");

			_theoraPacket++;
		}

		// look for more vorbis header packets
		while (_vorbisPacket && (_vorbisPacket < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) {
			if (ret < 0)
				error("Error parsing Vorbis stream headers; corrupt stream?");

			if (vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket))
				error("Error parsing Vorbis stream headers; corrupt stream?");

			_vorbisPacket++;

			if (_vorbisPacket == 3)
				break;
		}

		// The header pages/packets will arrive before anything else we
		// care about, or the stream is not obeying spec

		if (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) {
			queuePage(&_oggPage); // demux into the appropriate stream
		} else {
			ret = bufferData(); // someone needs more data

			if (ret == 0)
				error("End of file while searching for codec headers.");
		}
	}

	// and now we have it all.  initialize decoders
	if (_theoraPacket) {
		_theoraDecode = th_decode_alloc(&_theoraInfo, _theoraSetup);
		debugN(1, "Ogg logical stream %lx is Theora %dx%d %.02f fps",
		       _theoraOut.serialno, _theoraInfo.pic_width, _theoraInfo.pic_height,
		       (double)_theoraInfo.fps_numerator / _theoraInfo.fps_denominator);

		switch (_theoraInfo.pixel_fmt) {
		case TH_PF_420:
			debug(1, " 4:2:0 video");
			break;
		case TH_PF_422:
			debug(1, " 4:2:2 video");
			break;
		case TH_PF_444:
			debug(1, " 4:4:4 video");
			break;
		case TH_PF_RSVD:
		default:
			debug(1, " video\n  (UNKNOWN Chroma sampling!)");
			break;
		}

		if (_theoraInfo.pic_width != _theoraInfo.frame_width || _theoraInfo.pic_height != _theoraInfo.frame_height)
			debug(1, "  Frame content is %dx%d with offset (%d,%d).",
			      _theoraInfo.frame_width, _theoraInfo.frame_height, _theoraInfo.pic_x, _theoraInfo.pic_y);

		switch (_theoraInfo.colorspace){
		case TH_CS_UNSPECIFIED:
			/* nothing to report */
			break;
		case TH_CS_ITU_REC_470M:
			debug(1, "  encoder specified ITU Rec 470M (NTSC) color.");
			break;
		case TH_CS_ITU_REC_470BG:
			debug(1, "  encoder specified ITU Rec 470BG (PAL) color.");
			break;
		default:
			debug(1, "warning: encoder specified unknown colorspace (%d).", _theoraInfo.colorspace);
			break;
		}

		debug(1, "Encoded by %s", _theoraComment.vendor);
		if (_theoraComment.comments) {
			debug(1, "theora comment header:");
			for (int i = 0; i < _theoraComment.comments; i++) {
				if (_theoraComment.user_comments[i]) {
					int len = _theoraComment.comment_lengths[i];
					char *value = (char *)malloc(len + 1);
					if (value) {
						memcpy(value, _theoraComment.user_comments[i], len);
						value[len] = '\0';
						debug(1, "\t%s", value);
						free(value);
					}
				}
			}
		}

		th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &_ppLevelMax, sizeof(_ppLevelMax));
		_ppLevel = _ppLevelMax;
		th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel));
		_ppInc = 0;
	} else {
		// tear down the partial theora setup
		th_info_clear(&_theoraInfo);
		th_comment_clear(&_theoraComment);
	}

	th_setup_free(_theoraSetup);
	_theoraSetup = 0;

	if (_vorbisPacket) {
		vorbis_synthesis_init(&_vorbisDSP, &_vorbisInfo);
		vorbis_block_init(&_vorbisDSP, &_vorbisBlock);
		debug(3, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.",
		      _vorbisOut.serialno, _vorbisInfo.channels, _vorbisInfo.rate);

		_audStream = Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels);

		// Get enough audio data to start us off
		while (_audStream->numQueuedStreams() == 0) {
			// Queue more data
			bufferData();
			while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0)
				queuePage(&_oggPage);

			queueAudio();
		}

		if (_audStream)
			g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _audHandle, _audStream, -1, getVolume(), getBalance());
	} else {
		// tear down the partial vorbis setup
		vorbis_info_clear(&_vorbisInfo);
		vorbis_comment_clear(&_vorbisComment);
		_endOfAudio = true;
	}

	_surface.create(_theoraInfo.frame_width, _theoraInfo.frame_height, g_system->getScreenFormat());

	// Set up a display surface
	_displaySurface.pixels = _surface.getBasePtr(_theoraInfo.pic_x, _theoraInfo.pic_y);
	_displaySurface.w = _theoraInfo.pic_width;
	_displaySurface.h = _theoraInfo.pic_height;
	_displaySurface.format = _surface.format;
	_displaySurface.pitch = _surface.pitch;

	// Set the frame rate
	_frameRate = Common::Rational(_theoraInfo.fps_numerator, _theoraInfo.fps_denominator);

	return true;
}
Exemplo n.º 23
0
void CDemoVideoRecorder::Init(int Width, int Height, int FPS, int Format, const char *pName)
{
    m_pSound = Kernel()->RequestInterface<ISound>();
    m_FPS = FPS;
    m_ScreenWidth = Width;
    m_ScreenHeight = Height;
    m_Format = Format;

    if (m_Format == IClient::DEMO_RECORD_FORMAT_OGV)
    {
        ogg_stream_init(&m_TheoraOggStreamState, rand());
        ogg_stream_init(&m_VorbisOggStreamState, rand());

        char aBuf[1024];
        if (str_find_rev(pName, "/"))
            str_format(aBuf, sizeof(aBuf), "%s.ogv", str_find_rev(pName, "/"));
        else if (str_find_rev(aBuf, "\\"))
            str_format(aBuf, sizeof(pName), "%s.ogv", str_find_rev(pName, "\\"));
        else
            str_format(aBuf, sizeof(aBuf), "%s.ogv", pName);
        m_OggFile = io_open(aBuf, IOFLAG_WRITE);

        //thread_sleep(10000);
        vorbis_info_init(&m_VorbisEncodingInfo);
        vorbis_encode_init_vbr(&m_VorbisEncodingInfo, 2, g_Config.m_SndRate, 1.0f); //2 ch - samplerate - quality 1
        vorbis_analysis_init(&m_VorbisState, &m_VorbisEncodingInfo);
        vorbis_block_init(&m_VorbisState, &m_VorbisBlock);

        vorbis_comment_init(&m_VorbisComment);
        ogg_packet header;
        ogg_packet header_comm;
        ogg_packet header_code;
        vorbis_analysis_headerout(&m_VorbisState, &m_VorbisComment, &header, &header_comm, &header_code);
        ogg_stream_packetin(&m_VorbisOggStreamState, &header);
        ogg_stream_packetin(&m_VorbisOggStreamState, &header_comm);
        ogg_stream_packetin(&m_VorbisOggStreamState, &header_code);


        th_info_init(&m_TheoraEncodingInfo);
        m_TheoraEncodingInfo.frame_width = m_ScreenWidth+15&~0xF;
        m_TheoraEncodingInfo.frame_height = m_ScreenHeight+15&~0xF;
        m_TheoraEncodingInfo.pic_width = m_ScreenWidth;
        m_TheoraEncodingInfo.pic_height = m_ScreenHeight;
        m_TheoraEncodingInfo.pic_x = m_TheoraEncodingInfo.frame_width - m_ScreenWidth>>1&~1;
        m_TheoraEncodingInfo.pic_y = m_TheoraEncodingInfo.frame_height - m_ScreenHeight>>1&~1;
        m_TheoraEncodingInfo.colorspace = TH_CS_UNSPECIFIED;
        m_TheoraEncodingInfo.fps_numerator = FPS; //fps
        m_TheoraEncodingInfo.fps_denominator = 1;
        m_TheoraEncodingInfo.aspect_numerator = -1;
        m_TheoraEncodingInfo.aspect_denominator = -1;
        m_TheoraEncodingInfo.pixel_fmt = TH_PF_444;
        m_TheoraEncodingInfo.target_bitrate = (int)(64870*(ogg_int64_t)48000>>16);
        m_TheoraEncodingInfo.quality = 32;
        m_TheoraEncodingInfo.keyframe_granule_shift = 0;
        m_pThreoraContext = th_encode_alloc(&m_TheoraEncodingInfo);
        int arg = TH_RATECTL_CAP_UNDERFLOW;
        th_encode_ctl(m_pThreoraContext, TH_ENCCTL_SET_RATE_FLAGS, &arg, sizeof(arg));
        th_comment CommentHeader;
        ogg_packet OggPacket;
        th_comment_init(&CommentHeader);
        mem_zero(&OggPacket, sizeof(OggPacket));


            //Flush
        //Step 1
        th_encode_flushheader(m_pThreoraContext, &CommentHeader, &OggPacket); // first header

        ogg_stream_packetin(&m_TheoraOggStreamState, &OggPacket);
        //
        ogg_page OggPage;
        ogg_stream_pageout(&m_TheoraOggStreamState, &OggPage);
        io_write(m_OggFile, OggPage.header, OggPage.header_len);
        io_write(m_OggFile, OggPage.body, OggPage.body_len);

        while(1)
        {
            ogg_page OggPage;
            if (ogg_stream_flush(&m_VorbisOggStreamState,&OggPage) == 0)
                break;
            io_write(m_OggFile, OggPage.header, OggPage.header_len);
            io_write(m_OggFile, OggPage.body, OggPage.body_len);
        }

        while(th_encode_flushheader(m_pThreoraContext, &CommentHeader, &OggPacket))
        {
            ogg_stream_packetin(&m_TheoraOggStreamState, &OggPacket);
        }

        ogg_stream_flush(&m_TheoraOggStreamState, &OggPage);
        io_write(m_OggFile, OggPage.header, OggPage.header_len);
        io_write(m_OggFile, OggPage.body, OggPage.body_len);
    }
Exemplo n.º 24
0
OSErr init_theora_decoder(Theora_Globals glob, CodecDecompressParams *p)
{
    OSErr err = noErr;
    Handle ext;
    //OggSerialNoAtom *atom;
    Byte *ptrheader, *mCookie, *cend;
    UInt32 mCookieSize;
    CookieAtomHeader *aheader;
    th_comment tc;
    ogg_packet header, header_tc, header_cb;

    if (glob->info_initialised) {
        dbg_printf("--:Theora:- Decoder already initialised, skipping...\n");
        return err;
    }

    err = GetImageDescriptionExtension(p->imageDescription, &ext, kSampleDescriptionExtensionTheora, 1);
    if (err != noErr) {
        dbg_printf("XXX GetImageDescriptionExtension() failed! ('%4.4s')\n", &(*p->imageDescription)->cType);
        err = codecBadDataErr;
        return err;
    }

    mCookie = (UInt8 *) *ext;
    mCookieSize = GetHandleSize(ext);

    ptrheader = mCookie;
    cend = mCookie + mCookieSize;

    aheader = (CookieAtomHeader*)ptrheader;


    header.bytes = header_tc.bytes = header_cb.bytes = 0;

    while (ptrheader < cend) {
        aheader = (CookieAtomHeader *) ptrheader;
        ptrheader += EndianU32_BtoN(aheader->size);
        if (ptrheader > cend || EndianU32_BtoN(aheader->size) <= 0)
            break;

        switch(EndianS32_BtoN(aheader->type)) {
        case kCookieTypeTheoraHeader:
            header.b_o_s = 1;
            header.e_o_s = 0;
            header.granulepos = 0;
            header.packetno = 0;
            header.bytes = EndianS32_BtoN(aheader->size) - 2 * sizeof(long);
            header.packet = aheader->data;
            break;

        case kCookieTypeTheoraComments:
            header_tc.b_o_s = 0;
            header_tc.e_o_s = 0;
            header_tc.granulepos = 0;
            header_tc.packetno = 1;
            header_tc.bytes = EndianS32_BtoN(aheader->size) - 2 * sizeof(long);
            header_tc.packet = aheader->data;
            break;

        case kCookieTypeTheoraCodebooks:
            header_cb.b_o_s = 0;
            header_cb.e_o_s = 0;
            header_cb.granulepos = 0;
            header_cb.packetno = 2;
            header_cb.bytes = EndianS32_BtoN(aheader->size) - 2 * sizeof(long);
            header_cb.packet = aheader->data;
            break;

        default:
            break;
        }
    }

    err = codecBadDataErr;

    if (header.bytes == 0 || header_tc.bytes == 0 || header_cb.bytes == 0)
        return err;

    th_info_init(&glob->ti);
    th_comment_init(&tc);
    glob->ts = NULL;

    if (th_decode_headerin(&glob->ti, &tc, &glob->ts, &header) < 0) {

        if (glob->ts != NULL)
            th_setup_free (glob->ts);
        th_comment_clear(&tc);
        th_info_clear(&glob->ti);

        return err;
    }

    th_decode_headerin(&glob->ti, &tc, &glob->ts, &header_tc);
    th_decode_headerin(&glob->ti, &tc, &glob->ts, &header_cb);

    err = noErr;

    th_comment_clear(&tc);

    dbg_printf("--:Theora:- OK, managed to initialize the decoder somehow...\n");
    glob->info_initialised = true;

    return err;
}
Exemplo n.º 25
0
/*
 * init driver
 */
static int init(sh_video_t *sh){
    theora_struct_t *context = NULL;
    uint8_t *extradata = (uint8_t *)(sh->bih + 1);
    int extradata_size = sh->bih->biSize - sizeof(*sh->bih);
    int errorCode = 0;
    ogg_packet op;
    int i;

    context = calloc (sizeof (theora_struct_t), 1);
    sh->context = context;
    if (!context)
        goto err_out;

    th_info_init(&context->ti);
    th_comment_init(&context->tc);
    context->tsi = NULL;
	

    /* Read all header packets, pass them to theora_decode_header. */
    for (i = 0; i < THEORA_NUM_HEADER_PACKETS; i++)
    {
        if (extradata_size > 2) {
            op.bytes  = AV_RB16(extradata);
            op.packet = extradata + 2;
            op.b_o_s  = 1;
            if (extradata_size < op.bytes + 2) {
                mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Theora header too small\n");
                goto err_out;
            }
            extradata      += op.bytes + 2;
            extradata_size -= op.bytes + 2;
        } else {
            op.bytes = ds_get_packet (sh->ds, &op.packet);
            op.b_o_s = 1;
        }

        if ( (errorCode = th_decode_headerin (&context->ti, &context->tc, &context->tsi, &op)) < 0)
        {
            mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Broken Theora header; errorCode=%i!\n", errorCode);
            goto err_out;
        }
    }

    /* now init codec */
    context->tctx = th_decode_alloc (&context->ti, &context->tsi);
    if (!context->tctx)
    {
        mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Theora decode init failed\n");
        goto err_out;
    }
    /* free memory used for decoder setup information */
    th_setup_free(context->tsi);		

    if(sh->aspect==0.0 && context->ti.aspect_denominator!=0)
    {
       sh->aspect = ((double)context->ti.aspect_numerator * context->ti.frame_width)/
          ((double)context->ti.aspect_denominator * context->ti.frame_height);
    }

    mp_msg(MSGT_DECVIDEO,MSGL_V,"INFO: Theora video init ok!\n");
    mp_msg(MSGT_DECVIDEO,MSGL_INFO,"Frame: %dx%d, Picture %dx%d, Offset [%d,%d]\n", context->ti.frame_width, context->ti.frame_height, context->ti.pic_width, context->ti.pic_height, context->ti.pic_x, context->ti.pic_y);

    return mpcodecs_config_vo (sh,context->ti.frame_width,context->ti.frame_height,theora_pixelformat2imgfmt(context->ti.pixel_fmt));

err_out:
    free(context);
    sh->context = NULL;
    return 0;
}
Exemplo n.º 26
0
void VideoStreamPlaybackTheora::set_file(const String &p_file) {

	ERR_FAIL_COND(playing);
	ogg_packet op;
	th_setup_info *ts = NULL;

	file_name = p_file;
	if (file) {
		memdelete(file);
	}
	file = FileAccess::open(p_file, FileAccess::READ);
	ERR_FAIL_COND(!file);

#ifdef THEORA_USE_THREAD_STREAMING
	thread_exit = false;
	thread_eof = false;
	//pre-fill buffer
	int to_read = ring_buffer.space_left();
	int read = file->get_buffer(read_buffer.ptr(), to_read);
	ring_buffer.write(read_buffer.ptr(), read);

	thread = Thread::create(_streaming_thread, this);

#endif

	ogg_sync_init(&oy);

	/* init supporting Vorbis structures needed in header parsing */
	vorbis_info_init(&vi);
	vorbis_comment_init(&vc);

	/* init supporting Theora structures needed in header parsing */
	th_comment_init(&tc);
	th_info_init(&ti);

	theora_eos = false;
	vorbis_eos = false;

	/* Ogg file open; parse the headers */
	/* Only interested in Vorbis/Theora streams */
	int stateflag = 0;

	int audio_track_skip = audio_track;

	while (!stateflag) {
		int ret = buffer_data();
		if (ret == 0) break;
		while (ogg_sync_pageout(&oy, &og) > 0) {
			ogg_stream_state test;

			/* is this a mandated initial header? If not, stop parsing */
			if (!ogg_page_bos(&og)) {
				/* don't leak the page; get it into the appropriate stream */
				queue_page(&og);
				stateflag = 1;
				break;
			}

			ogg_stream_init(&test, ogg_page_serialno(&og));
			ogg_stream_pagein(&test, &og);
			ogg_stream_packetout(&test, &op);

			/* identify the codec: try theora */
			if (!theora_p && th_decode_headerin(&ti, &tc, &ts, &op) >= 0) {
				/* it is theora */
				copymem(&to, &test, sizeof(test));
				theora_p = 1;
			} else if (!vorbis_p && vorbis_synthesis_headerin(&vi, &vc, &op) >= 0) {

				/* it is vorbis */
				if (audio_track_skip) {
					vorbis_info_clear(&vi);
					vorbis_comment_clear(&vc);
					ogg_stream_clear(&test);
					vorbis_info_init(&vi);
					vorbis_comment_init(&vc);

					audio_track_skip--;
				} else {
					copymem(&vo, &test, sizeof(test));
					vorbis_p = 1;
				}
			} else {
				/* whatever it is, we don't care about it */
				ogg_stream_clear(&test);
			}
		}
		/* fall through to non-bos page parsing */
	}

	/* we're expecting more header packets. */
	while ((theora_p && theora_p < 3) || (vorbis_p && vorbis_p < 3)) {
		int ret;

		/* look for further theora headers */
		while (theora_p && (theora_p < 3) && (ret = ogg_stream_packetout(&to, &op))) {
			if (ret < 0) {
				fprintf(stderr, "Error parsing Theora stream headers; "
								"corrupt stream?\n");
				clear();
				return;
			}
			if (!th_decode_headerin(&ti, &tc, &ts, &op)) {
				fprintf(stderr, "Error parsing Theora stream headers; "
								"corrupt stream?\n");
				clear();
				return;
			}
			theora_p++;
		}

		/* look for more vorbis header packets */
		while (vorbis_p && (vorbis_p < 3) && (ret = ogg_stream_packetout(&vo, &op))) {
			if (ret < 0) {
				fprintf(stderr, "Error parsing Vorbis stream headers; corrupt stream?\n");
				clear();
				return;
			}
			ret = vorbis_synthesis_headerin(&vi, &vc, &op);
			if (ret) {
				fprintf(stderr, "Error parsing Vorbis stream headers; corrupt stream?\n");
				clear();
				return;
			}
			vorbis_p++;
			if (vorbis_p == 3) break;
		}

		/* The header pages/packets will arrive before anything else we
		care about, or the stream is not obeying spec */

		if (ogg_sync_pageout(&oy, &og) > 0) {
			queue_page(&og); /* demux into the appropriate stream */
		} else {
			int ret = buffer_data(); /* someone needs more data */
			if (ret == 0) {
				fprintf(stderr, "End of file while searching for codec headers.\n");
				clear();
				return;
			}
		}
	}

	/* and now we have it all.  initialize decoders */
	if (theora_p) {
		td = th_decode_alloc(&ti, ts);
		printf("Ogg logical stream %lx is Theora %dx%d %.02f fps",
				to.serialno, ti.pic_width, ti.pic_height,
				(double)ti.fps_numerator / ti.fps_denominator);
		px_fmt = ti.pixel_fmt;
		switch (ti.pixel_fmt) {
			case TH_PF_420: printf(" 4:2:0 video\n"); break;
			case TH_PF_422: printf(" 4:2:2 video\n"); break;
			case TH_PF_444: printf(" 4:4:4 video\n"); break;
			case TH_PF_RSVD:
			default:
				printf(" video\n  (UNKNOWN Chroma sampling!)\n");
				break;
		}
		if (ti.pic_width != ti.frame_width || ti.pic_height != ti.frame_height)
			printf("  Frame content is %dx%d with offset (%d,%d).\n",
					ti.frame_width, ti.frame_height, ti.pic_x, ti.pic_y);
		th_decode_ctl(td, TH_DECCTL_GET_PPLEVEL_MAX, &pp_level_max,
				sizeof(pp_level_max));
		pp_level = 0;
		th_decode_ctl(td, TH_DECCTL_SET_PPLEVEL, &pp_level, sizeof(pp_level));
		pp_inc = 0;

		int w;
		int h;
		w = (ti.pic_x + ti.frame_width + 1 & ~1) - (ti.pic_x & ~1);
		h = (ti.pic_y + ti.frame_height + 1 & ~1) - (ti.pic_y & ~1);
		size.x = w;
		size.y = h;

		texture->create(w, h, Image::FORMAT_RGBA8, Texture::FLAG_FILTER | Texture::FLAG_VIDEO_SURFACE);

	} else {
		/* tear down the partial theora setup */
		th_info_clear(&ti);
		th_comment_clear(&tc);
	}

	th_setup_free(ts);

	if (vorbis_p) {
		vorbis_synthesis_init(&vd, &vi);
		vorbis_block_init(&vd, &vb);
		fprintf(stderr, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.\n",
				vo.serialno, vi.channels, vi.rate);
		//_setup(vi.channels, vi.rate);

	} else {
		/* tear down the partial vorbis setup */
		vorbis_info_clear(&vi);
		vorbis_comment_clear(&vc);
	}

	playing = false;
	buffering = true;
	time = 0;
	audio_frames_wrote = 0;
};
Exemplo n.º 27
0
void TheoraPlayer::OpenFile(const String &path)
{
    ReleaseData();
    
    if(path == "")
        return;
    
    filePath = path;
    
    file = File::Create(path, File::OPEN | File::READ);
    ogg_sync_init(&theoraData->syncState);
    th_info_init(&theoraData->thInfo);
    th_comment_init(&theoraData->thComment);
    
    int32 stateflag = 0;
    while(!stateflag)
    {
        if(!BufferData())
            break;
        
        while(ogg_sync_pageout(&theoraData->syncState, &theoraData->page) > 0)
        {
            ogg_stream_state test;
            
            /* is this a mandated initial header? If not, stop parsing */
            if(!ogg_page_bos(&theoraData->page))
            {
                /* don't leak the page; get it into the appropriate stream */
                ogg_stream_pagein(&theoraData->state, &theoraData->page);
                stateflag = 1;
                break;
            }
            
            ogg_stream_init(&test, ogg_page_serialno(&theoraData->page));
            ogg_stream_pagein(&test, &theoraData->page);
            ogg_stream_packetout(&test, &theoraData->packet);
            
            /* identify the codec: try theora */
            if(!theora_p && th_decode_headerin(&theoraData->thInfo, &theoraData->thComment, &theoraData->thSetup, &theoraData->packet) >= 0)
            {
                /* it is theora */
                memcpy(&theoraData->state, &test, sizeof(test));
                theora_p = 1;
            }
            else
            {
                /* whatever it is, we don't care about it */
                ogg_stream_clear(&test);
            }
        }
        /* fall through to non-bos page parsing */
    }
    
    while(theora_p && theora_p < 3)
    {
        int ret;
        
        /* look for further theora headers */
        while(theora_p && (theora_p < 3) && (ret = ogg_stream_packetout(&theoraData->state, &theoraData->packet)))
        {
            if(ret < 0)
            {
                Logger::Error("TheoraPlayer: Error parsing Theora stream headers; corrupt stream?\n");
                return;
            }
            if(!th_decode_headerin(&theoraData->thInfo, &theoraData->thComment, &theoraData->thSetup, &theoraData->packet))
            {
                Logger::Error("TheoraPlayer: Error parsing Theora stream headers; corrupt stream?\n");
                return;
            }
            theora_p++;
        }
        
        /* The header pages/packets will arrive before anything else we
         care about, or the stream is not obeying spec */
        
        if(ogg_sync_pageout(&theoraData->syncState, &theoraData->page) > 0)
        {
            ogg_stream_pagein(&theoraData->state, &theoraData->page); /* demux into the appropriate stream */
        }
        else
        {
            int ret = BufferData(); /* someone needs more data */
            if(ret == 0)
            {
                Logger::Error("TheoraPlayer: End of file while searching for codec headers.\n");
                return;
            }
        }
    }
    if(theora_p)
    {
        theoraData->thCtx = th_decode_alloc(&theoraData->thInfo, theoraData->thSetup);
        
        th_decode_ctl(theoraData->thCtx, TH_DECCTL_GET_PPLEVEL_MAX, &pp_level_max, sizeof(pp_level_max));
        pp_level=pp_level_max;
        th_decode_ctl(theoraData->thCtx, TH_DECCTL_SET_PPLEVEL, &pp_level, sizeof(pp_level));
        pp_inc=0;
    }
    else
    {
        /* tear down the partial theora setup */
        th_info_clear(&theoraData->thInfo);
        th_comment_clear(&theoraData->thComment);
    }
    
    if(theoraData->thSetup)
        th_setup_free(theoraData->thSetup);
    theoraData->thSetup = 0;

    frameBufferW = binCeil(theoraData->thInfo.pic_width);
    frameBufferH = binCeil(theoraData->thInfo.pic_height);
    
    frameBuffer = new unsigned char[frameBufferW * frameBufferH * 4];
    
    repeatFilePos = file->GetPos();
    
    frameTime = (float32)(theoraData->thInfo.fps_denominator)/(float32)(theoraData->thInfo.fps_numerator);
    
    isPlaying = true;
}