Ejemplo n.º 1
0
/* Reads in buffers, parses them, reframes into one-buffer-per-ogg-page, submits
 * pages to output pad.
 */
static GstFlowReturn
gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
{
  GstOggParse *ogg;
  GstFlowReturn result = GST_FLOW_OK;
  gint ret = -1;
  guint32 serialno;
  GstBuffer *pagebuffer;
  GstClockTime buffertimestamp = GST_BUFFER_TIMESTAMP (buffer);

  ogg = GST_OGG_PARSE (GST_OBJECT_PARENT (pad));

  GST_LOG_OBJECT (ogg, "Chain function received buffer of size %d",
      GST_BUFFER_SIZE (buffer));

  gst_ogg_parse_submit_buffer (ogg, buffer);

  while (ret != 0 && result == GST_FLOW_OK) {
    ogg_page page;

    /* We use ogg_sync_pageseek() rather than ogg_sync_pageout() so that we can
     * track how many bytes the ogg layer discarded (in the case of sync errors,
     * etc.); this allows us to accurately track the current stream offset
     */
    ret = ogg_sync_pageseek (&ogg->sync, &page);
    if (ret == 0) {
      /* need more data, that's fine... */
      break;
    } else if (ret < 0) {
      /* discontinuity; track how many bytes we skipped (-ret) */
      ogg->offset -= ret;
    } else {
#ifndef GST_DISABLE_GST_DEBUG
      gint64 granule = ogg_page_granulepos (&page);
      int bos = ogg_page_bos (&page);
#endif
      guint64 startoffset = ogg->offset;

      GST_LOG_OBJECT (ogg, "Timestamping outgoing buffer as %" GST_TIME_FORMAT,
          GST_TIME_ARGS (buffertimestamp));
      /* Turn our page into a GstBuffer TODO: better timestamps? Requires format
       * parsing. */
      pagebuffer = gst_ogg_parse_buffer_from_page (&page, startoffset, FALSE,
          buffertimestamp);

      /* We read out 'ret' bytes, so we set the next offset appropriately */
      ogg->offset += ret;

      serialno = ogg_page_serialno (&page);

      GST_LOG_OBJECT (ogg,
          "processing ogg page (serial %08x, pageno %ld, "
          "granule pos %" G_GUINT64_FORMAT ", bos %d, offset %"
          G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT ")",
          serialno, ogg_page_pageno (&page),
          granule, bos, startoffset, ogg->offset);

      if (ogg_page_bos (&page)) {
        /* If we've seen this serialno before, this is technically an error,
         * we log this case but accept it - this one replaces the previous
         * stream with this serialno. We can do this since we're streaming, and
         * not supporting seeking...
         */
        GstOggStream *stream = gst_ogg_parse_find_stream (ogg, serialno);

        if (stream != NULL) {
          GST_LOG_OBJECT (ogg, "Incorrect stream; repeats serial number %u "
              "at offset %lld", serialno, ogg->offset);
        }

        if (ogg->last_page_not_bos) {
          GST_LOG_OBJECT (ogg, "Deleting all referenced streams, found a new "
              "chain starting with serial %u", serialno);
          gst_ogg_parse_delete_all_streams (ogg);
        }

        stream = gst_ogg_parse_new_stream (ogg, serialno);

        ogg->last_page_not_bos = FALSE;

        gst_buffer_ref (pagebuffer);
        stream->headers = g_slist_append (stream->headers, pagebuffer);

        if (!ogg->in_headers) {
          GST_LOG_OBJECT (ogg, "Found start of new chain at offset %llu",
              startoffset);
          ogg->in_headers = 1;
        }

        /* For now, we just keep the header buffer in the stream->headers list;
         * it actually gets output once we've collected the entire set
         */
      } else {
        /* Non-BOS page. Either: we're outside headers, and this isn't a 
         * header (normal data), outside headers and this is (error!), inside
         * headers, this is (append header), or inside headers and this isn't 
         * (we've found the end of headers; flush the lot!)
         *
         * Before that, we flag that the last page seen (this one) was not a 
         * BOS page; that way we know that when we next see a BOS page it's a
         * new chain, and we can flush all existing streams.
         */
        page_type type;
        GstOggStream *stream = gst_ogg_parse_find_stream (ogg, serialno);

        if (!stream) {
          GST_LOG_OBJECT (ogg, "Non-BOS page unexpectedly found at %lld",
              ogg->offset);
          goto failure;
        }

        ogg->last_page_not_bos = TRUE;

        type = gst_ogg_parse_is_header (ogg, stream, &page);

        if (type == PAGE_PENDING && ogg->in_headers) {
          gst_buffer_ref (pagebuffer);

          stream->unknown_pages = g_slist_append (stream->unknown_pages,
              pagebuffer);
        } else if (type == PAGE_HEADER) {
          if (!ogg->in_headers) {
            GST_LOG_OBJECT (ogg, "Header page unexpectedly found outside "
                "headers at offset %lld", ogg->offset);
            goto failure;
          } else {
            /* Append the header to the buffer list, after any unknown previous
             * pages
             */
            stream->headers = g_slist_concat (stream->headers,
                stream->unknown_pages);
            g_slist_free (stream->unknown_pages);
            gst_buffer_ref (pagebuffer);
            stream->headers = g_slist_append (stream->headers, pagebuffer);
          }
        } else {                /* PAGE_DATA, or PAGE_PENDING but outside headers */
          if (ogg->in_headers) {
            /* First non-header page... set caps, flush headers.
             *
             * First up, we build a single GValue list of all the pagebuffers
             * we're using for the headers, in order.
             * Then we set this on the caps structure. Then we can start pushing
             * buffers for the headers, and finally we send this non-header
             * page.
             */
            GstCaps *caps;
            GstStructure *structure;
            GValue array = { 0 };
            gint count = 0;
            gboolean found_pending_headers = FALSE;
            GSList *l;

            g_value_init (&array, GST_TYPE_ARRAY);

            for (l = ogg->oggstreams; l != NULL; l = l->next) {
              GstOggStream *stream = (GstOggStream *) l->data;

              if (g_slist_length (stream->headers) == 0) {
                GST_LOG_OBJECT (ogg, "No primary header found for stream %u",
                    stream->serialno);
                goto failure;
              }

              gst_ogg_parse_append_header (&array,
                  GST_BUFFER (stream->headers->data));
              count++;
            }

            for (l = ogg->oggstreams; l != NULL; l = l->next) {
              GstOggStream *stream = (GstOggStream *) l->data;
              int j;

              for (j = 1; j < g_slist_length (stream->headers); j++) {
                gst_ogg_parse_append_header (&array,
                    GST_BUFFER (g_slist_nth_data (stream->headers, j)));
                count++;
              }
            }

            caps = gst_pad_get_caps (ogg->srcpad);
            caps = gst_caps_make_writable (caps);

            structure = gst_caps_get_structure (caps, 0);
            gst_structure_set_value (structure, "streamheader", &array);

            gst_pad_set_caps (ogg->srcpad, caps);

            g_value_unset (&array);

            if (ogg->caps)
              gst_caps_unref (ogg->caps);
            ogg->caps = caps;

            GST_LOG_OBJECT (ogg, "Set \"streamheader\" caps with %d buffers "
                "(one per page)", count);

            /* Now, we do the same thing, but push buffers... */
            for (l = ogg->oggstreams; l != NULL; l = l->next) {
              GstOggStream *stream = (GstOggStream *) l->data;
              GstBuffer *buf = GST_BUFFER (stream->headers->data);

              gst_buffer_set_caps (buf, caps);

              result = gst_pad_push (ogg->srcpad, buf);
              if (result != GST_FLOW_OK)
                return result;
            }
            for (l = ogg->oggstreams; l != NULL; l = l->next) {
              GstOggStream *stream = (GstOggStream *) l->data;
              int j;

              for (j = 1; j < g_slist_length (stream->headers); j++) {
                GstBuffer *buf =
                    GST_BUFFER (g_slist_nth_data (stream->headers, j));
                gst_buffer_set_caps (buf, caps);

                result = gst_pad_push (ogg->srcpad, buf);
                if (result != GST_FLOW_OK)
                  return result;
              }
            }

            ogg->in_headers = 0;

            /* And finally the pending data pages */
            for (l = ogg->oggstreams; l != NULL; l = l->next) {
              GstOggStream *stream = (GstOggStream *) l->data;
              GSList *k;

              if (stream->unknown_pages == NULL)
                continue;

              if (found_pending_headers) {
                GST_WARNING_OBJECT (ogg, "Incorrectly muxed headers found at "
                    "approximate offset %lld", ogg->offset);
              }
              found_pending_headers = TRUE;

              GST_LOG_OBJECT (ogg, "Pushing %d pending pages after headers",
                  g_slist_length (stream->unknown_pages) + 1);

              for (k = stream->unknown_pages; k != NULL; k = k->next) {
                GstBuffer *buf;

                buf = GST_BUFFER (k->data);
                gst_buffer_set_caps (buf, caps);
                result = gst_pad_push (ogg->srcpad, buf);
                if (result != GST_FLOW_OK)
                  return result;
              }
              g_slist_foreach (stream->unknown_pages,
                  (GFunc) gst_mini_object_unref, NULL);
              g_slist_free (stream->unknown_pages);
              stream->unknown_pages = NULL;
            }

            gst_buffer_set_caps (pagebuffer, caps);

            result = gst_pad_push (ogg->srcpad, GST_BUFFER (pagebuffer));
            if (result != GST_FLOW_OK)
              return result;
          } else {
            /* Normal data page, submit buffer */
            gst_buffer_set_caps (pagebuffer, ogg->caps);
            result = gst_pad_push (ogg->srcpad, GST_BUFFER (pagebuffer));
            if (result != GST_FLOW_OK)
              return result;
          }
        }
      }
    }
  }

  return result;

failure:
  gst_pad_push_event (GST_PAD (ogg->srcpad), gst_event_new_eos ());
  return GST_FLOW_ERROR;
}
Ejemplo n.º 2
0
Archivo: ogg.c Proyecto: Erikhht/TCPMP
static int ReadPacketTime( ogg* p, format_reader* Reader, format_packet* Packet )
{
	// only called by CalcDuration

	format_buffer* Buffer;
	int Bytes;
	ogg_buffer* Ptr;
	ogg_sync_state* Sync = ogg_sync_create();
	ogg_page Page;

	if (!Sync)
		return ERR_OUT_OF_MEMORY;

	while ((Buffer = Format_BufferRemove(Reader))!=NULL)
	{
		Ptr = ogg_sync_bufferinext(Sync);
		if (Ptr)
		{
			Ptr->ext = &p->Format;
			Ptr->extdata = Buffer;
			Ptr->data = Buffer->Block.Ptr;
			Ptr->size = Buffer->Length;
			ogg_sync_wrote(Sync,Buffer->Length);
		}
		else
			Format_BufferRelease(&p->Format,Buffer);
	}

	memset(&Page,0,sizeof(Page));

	while ((Bytes = ogg_sync_pageseek(Sync,&Page)) != 0)
	{
		if (Bytes > 0)
		{
			int64_t MediaTime = ogg_page_granulepos(&Page);
			int	Id = ogg_page_serialno(&Page);
			int i;

			if (MediaTime != -1)
				for (i=0;i<p->Format.StreamCount;++i)
					if (p->Format.Streams[i]->Id == Id)
					{
						oggstream* s = (oggstream*) p->Format.Streams[i];

						if (s->MediaRateNum)
						{
							tick_t RefTime = (tick_t)((MediaTime * s->MediaRateDen) / s->MediaRateNum);
							
							if (RefTime > Packet->RefTime)
							{
								Packet->Stream = &s->Stream;
								Packet->RefTime = RefTime;
							}
						}
						break;
					}
		}
	}

	ogg_page_release(&Page);
	ogg_sync_destroy(Sync);

	return ERR_NONE;
}
Ejemplo n.º 3
0
void probe_ogg(info_t *ipipe)
{
    ogg_sync_state    sync;
    ogg_page          page;
    ogg_packet        pack;
    char             *buf;
    int               nread, np, sno, nvtracks = 0, natracks = 0, i, idx;
    //int               endofstream = 0, k, n;
    struct demux_t    streams[MAX_AUDIO_TRACKS + MAX_VIDEO_TRACKS];
    int               fdin = -1;
    char vid_codec[5];
    ogm_stream_header *sth;

    fdin = ipipe->fd_in;

    if (fdin == -1) {
	tc_log_error(__FILE__, "Could not open file.");
	goto ogg_out;
    }

    ipipe->probe_info->magic=TC_MAGIC_OGG;

    memset(streams, 0, sizeof(streams));
    for (i = 0; i < (MAX_AUDIO_TRACKS + MAX_VIDEO_TRACKS); i++)
	streams[i].serial = -1;

    ogg_sync_init(&sync);

    while (1) {
	np = ogg_sync_pageseek(&sync, &page);
	if (np < 0) {
	    tc_log_error(__FILE__, "ogg_sync_pageseek failed");
	    goto ogg_out;
	}
	if (np == 0) {
	    buf = ogg_sync_buffer(&sync, BLOCK_SIZE);
	    if (!buf) {
		tc_log_error(__FILE__, "ogg_sync_buffer failed");
		goto ogg_out;
	    }

	    if ((nread = read(fdin, buf, BLOCK_SIZE)) <= 0) {
	    }
	    ogg_sync_wrote(&sync, nread);
	    continue;
	}

	if (!ogg_page_bos(&page)) {
	    break;
	} else {
	    ogg_stream_state sstate;
	    vorbis_info *inf = tc_malloc (sizeof(vorbis_info));
	    vorbis_comment *com = tc_malloc (sizeof(vorbis_comment));

	    if (!inf || !com) {
		tc_log_error(__FILE__, "Out of Memory at %d", __LINE__);
		goto ogg_out;
	    }
	    sno = ogg_page_serialno(&page);
	    if (ogg_stream_init(&sstate, sno)) {
		tc_log_error(__FILE__, "ogg_stream_init failed");
		goto ogg_out;
	    }
	    ogg_stream_pagein(&sstate, &page);
	    ogg_stream_packetout(&sstate, &pack);

	    switch (ogm_packet_type(pack))
	    {
		case Vorbis:
		    vorbis_info_init(inf);
		    vorbis_comment_init(com);

		    if(vorbis_synthesis_headerin(inf, com, &pack) < 0) {
			tc_log_warn(__FILE__, "Could not decode vorbis header "
				    "packet - invalid vorbis stream ()");
		    } else {
#ifdef OGM_DEBUG
			tc_log_msg(__FILE__, "(a%d/%d) Vorbis audio; "
				"rate: %ldHz, channels: %d, bitrate %3.2f kb/s",
				natracks + 1, natracks + nvtracks + 1, inf->rate,
				inf->channels, (double)inf->bitrate_nominal/1000.0);
#endif

			ipipe->probe_info->track[natracks].samplerate = inf->rate;
			ipipe->probe_info->track[natracks].chan = inf->channels;
			ipipe->probe_info->track[natracks].bits = 0; /* XXX --tibit*/
			ipipe->probe_info->track[natracks].format = TC_CODEC_VORBIS;
			ipipe->probe_info->track[natracks].bitrate = (double)inf->bitrate_nominal/1000.0;

			ipipe->probe_info->track[natracks].tid=natracks;
			if(ipipe->probe_info->track[natracks].chan>0) ++ipipe->probe_info->num_tracks;

			streams[natracks].serial = sno;
			streams[natracks].vorbis = 1;
			ac_memcpy(&streams[natracks].state, &sstate, sizeof(sstate));
			natracks++;
		    }
		    break;
#ifdef HAVE_THEORA
		case Theora:
		{
		    theora_info ti;
		    theora_comment tc;

		    theora_decode_header(&ti, &tc, &pack);

		    ipipe->probe_info->width  =  ti.width;
		    ipipe->probe_info->height =  ti.height;
		    ipipe->probe_info->fps    =  (double)ti.fps_numerator/ti.fps_denominator;
		    tc_frc_code_from_ratio(&(ipipe->probe_info->frc),
		    	    		   ti.fps_numerator, ti.fps_denominator);

		    ipipe->probe_info->codec=TC_CODEC_THEORA;

		    idx = natracks + MAX_AUDIO_TRACKS;

		    streams[idx].serial = sno;
		    ac_memcpy(&streams[idx].state, &sstate, sizeof(sstate));
		    nvtracks++;
		    break;
	        }
#endif
		case DirectShow:
		    if ((*(int32_t*)(pack.packet+96) == 0x05589f80) &&
			    (pack.bytes >= 184)) {
			tc_log_warn(__FILE__, "(v%d/%d) Found old video "
				    "header. Not supported.", nvtracks + 1,
				    natracks + nvtracks + 1);
		    } else if (*(int32_t*)pack.packet+96 == 0x05589F81) {
			tc_log_warn(__FILE__, "(a%d/%d) Found old audio "
				    "header. Not supported.", natracks + 1,
				    natracks + nvtracks + 1);
		    }
		    break;
		case StreamHeader:
		    sth = (ogm_stream_header *)(pack.packet + 1);

		    if (!strncmp(sth->streamtype, "video", 5)) {
#ifdef OGM_DEBUG
			unsigned long codec;
			codec = (sth->subtype[0] << 24) +
			    (sth->subtype[1] << 16) + (sth->subtype[2] << 8) + sth->subtype[3];
			tc_log_msg(__FILE__, "(v%d/%d) video; fps: %.3f width height: %dx%d "
				"codec: %p (%c%c%c%c)", nvtracks + 1,
				natracks + nvtracks + 1,
				(double)10000000 / (double)sth->time_unit,
				sth->sh.video.width, sth->sh.video.height, (void *)codec,
				sth->subtype[0], sth->subtype[1], sth->subtype[2],
				sth->subtype[3]);
#endif
			vid_codec[0] = sth->subtype[0];
			vid_codec[1] = sth->subtype[1];
			vid_codec[2] = sth->subtype[2];
			vid_codec[3] = sth->subtype[3];
			vid_codec[4] = '\0';

			//ipipe->probe_info->frames = AVI_video_frames(avifile);

			ipipe->probe_info->width  =  sth->sh.video.width;
			ipipe->probe_info->height =  sth->sh.video.height;
			ipipe->probe_info->fps    =  (double)10000000 / (double)sth->time_unit;
			tc_frc_code_from_value(&(ipipe->probe_info->frc),
  						  ipipe->probe_info->fps);

			ipipe->probe_info->codec=TC_CODEC_UNKNOWN; // gets rewritten

			if(strlen(vid_codec)==0) {
			    ipipe->probe_info->codec=TC_CODEC_RGB24;
			} else {

			    if(strcasecmp(vid_codec,"dvsd")==0)
				ipipe->probe_info->codec=TC_CODEC_DV;

			    if(strcasecmp(vid_codec,"DIV3")==0)
				ipipe->probe_info->codec=TC_CODEC_DIVX3;

			    if(strcasecmp(vid_codec,"DIVX")==0)
				ipipe->probe_info->codec=TC_CODEC_DIVX4;

			    if(strcasecmp(vid_codec,"DX50")==0)
				ipipe->probe_info->codec=TC_CODEC_DIVX5;

			    if(strcasecmp(vid_codec,"XVID")==0)
				ipipe->probe_info->codec=TC_CODEC_XVID;

			    if(strcasecmp(vid_codec,"MJPG")==0)
				ipipe->probe_info->codec=TC_CODEC_MJPEG;
			}

			idx = natracks + MAX_AUDIO_TRACKS;

			streams[idx].serial = sno;
			ac_memcpy(&streams[idx].state, &sstate, sizeof(sstate));
			nvtracks++;
		    } else if (!strncmp(sth->streamtype, "audio", 5)) {
			int codec;
			char buf[5];
			ac_memcpy(buf, sth->subtype, 4);
			buf[4] = 0;
			codec = strtoul(buf, NULL, 16);
#ifdef OGM_DEBUG
			tc_log_msg(__FILE__, "(a%d/%d) codec: %d (0x%04x) (%s) bits per "
				   "sample: %d channels: %hd  samples per second: %ld "
				   "avgbytespersec: %hd blockalign: %d",
				   natracks + 1, natracks + nvtracks + 1,
				   codec, codec,
				   codec == 0x1 ? "PCM" : codec == 55 ? "MP3" :
				   codec == 0x55 ? "MP3" :
				   codec == 0x2000 ? "AC3" : "unknown",
				   sth->bits_per_sample, sth->sh.audio.channels,
				   (long)sth->samples_per_unit,
				   sth->sh.audio.avgbytespersec,
				   sth->sh.audio.blockalign);
#endif
			idx = natracks;

			ipipe->probe_info->track[natracks].samplerate = sth->samples_per_unit;
			ipipe->probe_info->track[natracks].chan = sth->sh.audio.channels;
			ipipe->probe_info->track[natracks].bits =
			    (sth->bits_per_sample<4)?sth->bits_per_sample*8:sth->bits_per_sample;
			ipipe->probe_info->track[natracks].format = codec;
			ipipe->probe_info->track[natracks].bitrate = 0;

			ipipe->probe_info->track[natracks].tid=natracks;


			if(ipipe->probe_info->track[natracks].chan>0) ++ipipe->probe_info->num_tracks;

			streams[idx].serial = sno;
			ac_memcpy(&streams[idx].state, &sstate, sizeof(sstate));
			natracks++;
		    } else {
			tc_log_warn(__FILE__, "(%d) found new header of unknown/"
				"unsupported type\n", nvtracks + natracks + 1);
		    }
		    break;
		case none:
		    tc_log_warn(__FILE__, "OGG stream %d is of an unknown type "
			"(bad header?)", nvtracks + natracks + 1);
		    break;
	    } /* switch type */
	    free(inf);
	    free(com);
	    ogg_stream_clear(&sstate);
	} /* beginning of page */
    } /* while (1) */
ogg_out:
    //close(fdin);
    return;
}
Ejemplo n.º 4
0
	void VideoClip_Theora::_load(DataSource* source)
	{
#ifdef _DEBUG
		log("-----");
#endif
		this->stream = source;
		this->_readTheoraVorbisHeaders();
		this->info.TheoraDecoder = th_decode_alloc(&this->info.TheoraInfo, this->info.TheoraSetup);
		this->width = this->info.TheoraInfo.frame_width;
		this->height = this->info.TheoraInfo.frame_height;
		this->subFrameWidth = this->info.TheoraInfo.pic_width;
		this->subFrameHeight = this->info.TheoraInfo.pic_height;
		this->subFrameX = this->info.TheoraInfo.pic_x;
		this->subFrameY = this->info.TheoraInfo.pic_y;
		this->stride = this->getWidth();
		if (this->useStride)
		{
			this->stride = potCeil(this->stride);
		}
		this->fps = this->info.TheoraInfo.fps_numerator / (float)this->info.TheoraInfo.fps_denominator;
#ifdef _DEBUG
		log("width: " + str(this->width) + ", height: " + str(this->height) + ", fps: " + str((int)this->getFps()));
#endif
		this->frameQueue = new FrameQueue(this);
		this->frameQueue->setSize(this->precachedFramesCount);
		// find out the duration of the file by seeking to the end
		// having ogg decode pages, extract the granule pos from
		// the last theora page and seek back to beginning of the file
		char* buffer = NULL;
		int bytesRead = 0;
		uint64_t streamSize = this->stream->getSize();
		uint64_t seekPos = 0;
		int result = 0;
		ogg_int64_t granule = 0;
		for (unsigned int i = 1; i <= 50; ++i)
		{
			ogg_sync_reset(&this->info.OggSyncState);
			seekPos = (BUFFER_SIZE * i > streamSize ? 0 : streamSize - BUFFER_SIZE * i);
			this->stream->seek(seekPos);
			buffer = ogg_sync_buffer(&this->info.OggSyncState, BUFFER_SIZE * i);
			bytesRead = this->stream->read(buffer, BUFFER_SIZE * i);
			ogg_sync_wrote(&this->info.OggSyncState, bytesRead);
			ogg_sync_pageseek(&this->info.OggSyncState, &this->info.OggPage);
			while (true)
			{
				result = ogg_sync_pageout(&this->info.OggSyncState, &this->info.OggPage);
				if (result == 0)
				{
					break;
				}
				// if page is not a theora page or page is unsynced(-1), skip it
				if (result == -1 || ogg_page_serialno(&this->info.OggPage) != this->info.TheoraStreamState.serialno)
				{
					continue;
				}
				granule = ogg_page_granulepos(&this->info.OggPage);
				if (granule >= 0)
				{
					this->framesCount = (int)th_granule_frame(this->info.TheoraDecoder, granule) + 1;
				}
				else if (this->framesCount > 0)
				{
					++this->framesCount; // append delta frames at the end to get the exact number
				}
			}
			if (this->framesCount > 0 || streamSize < BUFFER_SIZE * i)
			{
				break;
			}
		}
		if (this->framesCount < 0)
		{
			log("unable to determine file duration!");
		}
		else
		{
			this->duration = this->framesCount / this->fps;
#ifdef _DEBUG
			log("duration: " + strf(this->duration) + " seconds");
#endif
		}
		// restore to beginning of stream.
		ogg_sync_reset(&this->info.OggSyncState);
		this->stream->seek(0);
		if (this->vorbisStreams > 0) // if there is no audio interface factory defined, even though the video clip might have audio, it will be ignored
		{
			vorbis_synthesis_init(&this->info.VorbisDSPState, &this->info.VorbisInfo);
			vorbis_block_init(&this->info.VorbisDSPState, &this->info.VorbisBlock);
			this->audioChannelsCount = this->info.VorbisInfo.channels;
			this->audioFrequency = (int) this->info.VorbisInfo.rate;
			// create an audio interface instance if available
			AudioInterfaceFactory* audioInterfaceFactory = theoraplayer::manager->getAudioInterfaceFactory();
			if (audioInterfaceFactory != NULL)
			{
				this->setAudioInterface(audioInterfaceFactory->createInstance(this, this->audioChannelsCount, this->audioFrequency));
			}
		}
		this->frameDuration = 1.0f / this->getFps();
#ifdef _DEBUG
		log("-----");
#endif
	}
Ejemplo n.º 5
0
	long VideoClip_Theora::_seekPage(long targetFrame, bool returnKeyFrame)
	{
		uint64_t seekMin = 0;
		uint64_t seekMax = this->stream->getSize();
		long frame = 0;
		ogg_int64_t granule = 0;
		if (targetFrame == 0)
		{
			this->stream->seek(0);
		}
		char* buffer = NULL;
		int bytesRead = 0;
		if (targetFrame != 0)
		{
			for (int i = 0; i < 100; ++i)
			{
				ogg_sync_reset(&this->info.OggSyncState);
				this->stream->seek(seekMin / 2 + seekMax / 2); // do a binary search
				memset(&this->info.OggPage, 0, sizeof(ogg_page));
				ogg_sync_pageseek(&this->info.OggSyncState, &this->info.OggPage);
				while (i < 1000)
				{
					if (ogg_sync_pageout(&this->info.OggSyncState, &this->info.OggPage) == 1)
					{
						if (ogg_page_serialno(&this->info.OggPage) == this->info.TheoraStreamState.serialno)
						{
							granule = ogg_page_granulepos(&this->info.OggPage);
							if (granule >= 0)
							{
								frame = (long)th_granule_frame(this->info.TheoraDecoder, granule);
								if (frame < targetFrame && targetFrame - frame < 10)
								{
									// we're close enough, let's break this.
									i = 1000;
									break;
								}
								// we're not close enough, let's shorten the borders of the binary search
								if (targetFrame - 1 > frame)
								{
									seekMin = seekMin / 2 + seekMax / 2;
								}
								else
								{
									seekMax = seekMin / 2 + seekMax / 2;
								}
								break;
							}
						}
					}
					else
					{
						buffer = ogg_sync_buffer(&this->info.OggSyncState, BUFFER_SIZE);
						bytesRead = this->stream->read(buffer, BUFFER_SIZE);
						if (bytesRead == 0)
						{
							break;
						}
						ogg_sync_wrote(&this->info.OggSyncState, bytesRead);
					}
				}
			}
		}
		if (returnKeyFrame)
		{
			return (long)(granule >> this->info.TheoraInfo.keyframe_granule_shift);
		}
		ogg_sync_reset(&this->info.OggSyncState);
		memset(&this->info.OggPage, 0, sizeof(ogg_page));
		ogg_sync_pageseek(&this->info.OggSyncState, &this->info.OggPage);
		if (targetFrame == 0)
		{
			return -1;
		}
		this->stream->seek((seekMin + seekMax) / 2); // do a binary search
		return -1;
	}
Ejemplo n.º 6
0
status_t
OggReader::FindLastPages()
{
	TRACE("OggReader::FindLastPages\n");
	bigtime_t start_time = system_time();

	status_t result = B_ERROR;

	const int read_size = 256*256;

	ogg_page page;
	ogg_sync_state sync;
	ogg_sync_init(&sync);

	off_t right = fSeekable->Seek(0, SEEK_END);
	off_t left = right;
	// we assume the common case is that the last pages are near the end
	uint serial_count = 0;
	while (serial_count < fCookies.size()) {
		int offset;
		ssize_t bytes = 0;
		while ((offset = ogg_sync_pageseek(&sync, &page)) <= 0) {
			left += -offset;
			if (offset == 0) {
				off_t pos = fSeekable->Position();
				if (pos >= right || bytes == 0) {
					if (left == 0) {
						TRACE("OggReader::FindLastPages: couldn't find some stream's page!!!\n");
						goto done;
					}
					left = max_c(0, left - read_size);
					result = fSeekable->Seek(left, SEEK_SET);
					if (result < 0) {
						goto done;
					}
					ogg_sync_reset(&sync);
				}
				char * buffer = ogg_sync_buffer(&sync, read_size);
				bytes = fSeekable->Read(buffer, read_size);
				if (bytes < 0) {
					TRACE("OggReader::FindLastPages: Read: error\n");
					result = bytes;
					goto done;
				}
				if (ogg_sync_wrote(&sync, bytes) != 0) {
					TRACE("OggReader::FindLastPages: ogg_sync_wrote failed?: error\n");
					goto done;
				}
			}
		}
		off_t current = left;
		do {
			// found a page at "current"
			long serialno = ogg_page_serialno(&page);
			OggSeekable * track = dynamic_cast<OggSeekable*>(fTracks[serialno]);
			if (track == 0) {
				TRACE("OggReader::FindLastPages: unknown serialno == TODO: chaining?\n");
			} else {
				if (track->GetLastPagePosition() == 0) {
					serial_count++;
				}
				track->SetLastPagePosition(current);
			}
			current += page.header_len + page.body_len;
		} while ((current < right) && (ogg_sync_pageout(&sync, &page) == 1));
		right = left;
		ogg_sync_reset(&sync);
	}
	result = B_OK;
done:
	ogg_sync_clear(&sync);
	TRACE("OggReader::FindLastPages took %lld microseconds\n", system_time() - start_time);

	return result;
}
Ejemplo n.º 7
0
static int64_t find_first_page( demux_t *p_demux, int64_t i_pos1, int64_t i_pos2, 
                                logical_stream_t *p_stream, 
                                int64_t *pi_kframe, int64_t *pi_frame )
{
    int64_t i_result;
    int64_t i_granulepos;
    int64_t i_bytes_to_read = i_pos2 - i_pos1 + 1;
    int64_t i_bytes_read;
    int64_t i_pages_checked = 0;
    int64_t i_packets_checked;

    demux_sys_t *p_sys  = p_demux->p_sys;

    ogg_packet op;

    seek_byte( p_demux, i_pos1 );

    if ( i_pos1 == p_stream->i_data_start )
    {
        /* set a dummy granulepos at data_start */
        *pi_kframe = p_stream->i_keyframe_offset;
        *pi_frame = p_stream->i_keyframe_offset;

        p_sys->b_page_waiting = true;
        return p_sys->i_input_position;
    }

    if ( i_bytes_to_read > OGGSEEK_BYTES_TO_READ ) i_bytes_to_read = OGGSEEK_BYTES_TO_READ;

    while ( 1 )
    {

        if ( p_sys->i_input_position >= i_pos2 )
        {
            /* we reached the end and found no pages */
            *pi_frame=-1;
            return -1;
        }

        /* read next chunk */
        if ( ! ( i_bytes_read = get_data( p_demux, i_bytes_to_read ) ) )
        {
            /* EOF */
            *pi_frame = -1;
            return -1;
        }

        i_bytes_to_read = OGGSEEK_BYTES_TO_READ;

        i_result = ogg_sync_pageseek( &p_sys->oy, &p_sys->current_page );

        if ( i_result < 0 )
        {
            /* found a page, sync to page start */
            p_sys->i_input_position -= i_result;
            i_pos1 = p_sys->i_input_position;
            continue;
        }

        if ( i_result > 0 || ( i_result == 0 && p_sys->oy.fill > 3 && 
                               ! strncmp( (char *)p_sys->oy.data, "OggS" , 4 ) ) )
        {
            i_pos1 = p_sys->i_input_position;
            break;
        }

        p_sys->i_input_position += i_bytes_read;

    };

    seek_byte( p_demux, p_sys->i_input_position );
    ogg_stream_reset( &p_stream->os );

    while( 1 )
    {

        if ( p_sys->i_input_position >= i_pos2 )
        {
            /* reached the end of the search region and nothing was found */
            *pi_frame = -1;
            return p_sys->i_input_position;
        }

        p_sys->b_page_waiting = false;

        if ( ! ( i_result = oggseek_read_page( p_demux ) ) )
        {
            /* EOF */
            *pi_frame = -1;
            return p_sys->i_input_position;
        }

        // found a page
        if ( p_stream->os.serialno != ogg_page_serialno( &p_sys->current_page ) )
        {
            /* page is not for this stream */
            p_sys->i_input_position += i_result;
            if ( ! i_pages_checked ) i_pos1 = p_sys->i_input_position;
            continue;
        }


        ogg_stream_pagein( &p_stream->os, &p_sys->current_page );

        i_pages_checked++;
        i_packets_checked = 0;

        if ( ogg_stream_packetout( &p_stream->os, &op ) > 0 )
        {
            i_packets_checked++;
        }

        if ( i_packets_checked )
        {
            i_granulepos = ogg_page_granulepos( &p_sys->current_page );

            oggseek_theora_index_entry_add( p_stream, i_granulepos, i_pos1 );

            *pi_kframe =
                i_granulepos >> p_stream->i_granule_shift;

            *pi_frame = *pi_kframe +
                i_granulepos - ( *pi_kframe << p_stream->i_granule_shift );

            p_sys->b_page_waiting = true;
            return i_pos1;

        }

        /*  -> start of next page */
        p_sys->i_input_position += i_result;
    }
}