1 // LiVES - ogg/theora/dirac/vorbis decoder plugin
2 // (c) G. Finch 2008 - 2010 <salsaman@xs4all.nl,salsaman@gmail.com>
3 // released under the GNU GPL 3 or later
4 // see file COPYING or www.gnu.org for details
5 
6 // start decoding at the page whose granulepos converts to the highest frame number prior to the one you're looking for
7 
8 // TODO - split this into demuxer and decoders
9 
10 // ignore this, just some notes ----------
11 // decoders should have the functions:
12 // - recognise :: demuxer passes in the first packet of a stream, and a decoder claims it
13 //                decoder tells how many more bos packets it needs (detect_stream)
14 // - pre_init :: demuxer passes in bos packets until the decoder has parsed them all (setup tracks)
15 // - init :: decoder initialises its internal data (attach_stream)
16 // - set_data :: decoder completes cdata
17 
18 // - clear  :: decoder frees stuff (detach_stream)
19 
20 
21 // granulepos to pos :: demuxer passes in something like a granulepos or a byte offset, decoder returns kframe,frame or
22 //                      sample offset   [is this possible since it requires knowledge of demuxer and decoder ?]
23 //                      (granulepos_to_time)
24 
25 
26 // granulepos_2_frame and frame_2 _granulepos are problematic for splitting like this
27 
28 // - decode packet (and return if we got a frame out) (ogg_*_read)
29 
30 // - return same frame
31 
32 // finalise (clip_data_free)
33 ///----------------------------------------------------------
34 
35 #define NEED_CLONEFUNC
36 
37 #include "decplugin.h"
38 
39 ///////////////////////////////////////////////////////
40 #include <string.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <unistd.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <sched.h>
47 
48 #include <ogg/ogg.h>
49 
50 #ifdef HAVE_THEORA
51 #include <theora/theora.h>
52 #endif
53 
54 #ifdef HAVE_DIRAC
55 #include <schroedinger/schro.h>
56 #endif
57 
58 #include <pthread.h>
59 
60 #include "ogg_decoder.h"
61 
62 #define NEED_FOURCC_COMPAT
63 
64 #ifdef NEED_LOCAL_WEED
65 #include "../../../libweed/weed-compat.h"
66 #else
67 #include <weed/weed-compat.h>
68 #endif
69 
70 static boolean ogg_data_process(lives_clip_data_t *cdata, void *yuvbuffer, boolean cont);
71 
72 static const char *plname = "lives_ogg";
73 static int vmaj = 1;
74 static int vmin = 2;
75 static const char *plugin_version = "LiVES ogg decoder version 1.2";
76 
77 static index_container_t **indices;
78 static int nidxc;
79 static pthread_mutex_t indices_mutex;
80 
81 
82 /////////////////////////////////////////
83 // schroed stuff
84 
85 #ifdef HAVE_DIRAC
SchroFrameFree(SchroFrame * sframe,void * priv)86 static void SchroFrameFree(SchroFrame *sframe, void *priv) {
87   register int i;
88   for (i = 0; i < 3; i++) free(sframe->components[i].data);
89 }
90 
91 
SchroBufferFree(SchroBuffer * sbuf,void * priv)92 static void SchroBufferFree(SchroBuffer *sbuf, void *priv) {
93   free(priv);
94 }
95 
96 
97 #endif
98 
99 ////////////////////////////////////////////
100 
101 // index_entries
102 
103 
index_entries_free(index_entry * idx)104 static void index_entries_free(index_entry *idx) {
105   index_entry *idx_next;
106 
107   while (idx != NULL) {
108     idx_next = idx->next;
109     free(idx);
110     idx = idx_next;
111   }
112 }
113 
114 
index_entry_new(void)115 static index_entry *index_entry_new(void) {
116   index_entry *ie = (index_entry *)malloc(sizeof(index_entry));
117   ie->next = ie->prev = NULL;
118   ie->pagepos_end = -1;
119   return ie;
120 }
121 
122 
123 #ifdef HAVE_DIRAC
124 
index_entry_delete(index_entry * idx)125 static index_entry *index_entry_delete(index_entry *idx) {
126   // unlink and free idx. If idx is head of list, return new head.
127 
128   index_entry *xidx = idx;
129 
130   if (idx->prev != NULL) idx->prev->next = idx->next;
131   else xidx = idx->next;
132 
133   if (idx->next != NULL) idx->next->prev = idx->prev;
134   free(idx);
135 
136   return xidx;
137 }
138 
139 
find_pagepos_in_index(index_entry * idx,int64_t pagepos)140 static index_entry *find_pagepos_in_index(index_entry *idx, int64_t pagepos) {
141   while (idx != NULL) {
142     if (idx->pagepos <= pagepos && idx->pagepos_end >= pagepos) return idx;
143     idx = idx->next;
144   }
145   return NULL;
146 }
147 
148 #endif
149 
150 
theora_index_entry_add(lives_clip_data_t * cdata,int64_t granule,int64_t pagepos)151 static index_entry *theora_index_entry_add(lives_clip_data_t *cdata, int64_t granule, int64_t pagepos) {
152   // add or update entry for keyframe and return it
153   index_entry *idx, *oidx, *last_idx = NULL;
154   int64_t gpos, frame, kframe, tframe, tkframe;
155 
156   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
157 
158   if (priv->vstream == NULL) return NULL;
159 
160   tkframe = granule >> priv->vstream->stpriv->keyframe_granule_shift;
161   tframe = tkframe + granule - (tkframe << priv->vstream->stpriv->keyframe_granule_shift);
162 
163   if (tkframe < 1) return NULL;
164 
165   oidx = idx = priv->idxc->idx;
166 
167   if (!idx) {
168     index_entry *ie = index_entry_new();
169     ie->value = granule;
170     ie->pagepos = pagepos;
171     priv->idxc->idx = ie;
172     return ie;
173   }
174 
175   while (idx) {
176     gpos = idx->value;
177 
178     kframe = gpos >> priv->vstream->stpriv->keyframe_granule_shift;
179     if (kframe > tframe) break;
180 
181     if (kframe == tkframe) {
182       // entry exists, update it if applicable, and return it in found
183       frame = kframe + gpos - (kframe << priv->vstream->stpriv->keyframe_granule_shift);
184       if (frame < tframe) {
185         idx->value = granule;
186         idx->pagepos = pagepos;
187       }
188       return idx;
189     }
190 
191     last_idx = idx;
192     idx = idx->next;
193   }
194 
195   // insert after last_idx
196 
197   idx = index_entry_new();
198 
199   if (last_idx) {
200     idx->next = last_idx->next;
201     last_idx->next = idx;
202     idx->prev = last_idx;
203   } else {
204     idx->next = oidx;
205     oidx = idx;
206   }
207 
208   if (idx->next) {
209     idx->next->prev = idx;
210   }
211 
212   idx->value = granule;
213   idx->pagepos = pagepos;
214 
215   return idx;
216 }
217 
218 #ifdef HAVE_DIRAC
219 
dirac_index_entry_add_before(index_entry * idx,int64_t pagepos)220 static index_entry *dirac_index_entry_add_before(index_entry *idx, int64_t pagepos) {
221   index_entry *new_idx = index_entry_new();
222 
223   new_idx->value = -1;
224   new_idx->pagepos = pagepos;
225 
226   if (idx) {
227     new_idx->next = idx;
228     new_idx->prev = idx->prev;
229     if (idx->prev) idx->prev->next = new_idx;
230     idx->prev = new_idx;
231   }
232   return new_idx;
233 }
234 
235 
dirac_index_entry_add(lives_clip_data_t * cdata,int64_t pagepos,int64_t pagepos_end,int64_t frame)236 static index_entry *dirac_index_entry_add(lives_clip_data_t *cdata, int64_t pagepos, int64_t pagepos_end,
237     int64_t frame) {
238   // add a new entry in order, and return a pointer to it
239 
240   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
241   index_entry *new_idx = priv->idxc->idx, *last_idx = NULL;
242 
243   //printf("ADDING IDX for frame %ld region %ld to %ld\n",frame,pagepos,pagepos_end);
244 
245   //if (pagepos_end<pagepos) return NULL; // TODO ***
246 
247   while (new_idx) {
248     if (new_idx->pagepos > pagepos) {
249       new_idx = dirac_index_entry_add_before(new_idx, pagepos);
250       new_idx->value = frame;
251       new_idx->pagepos_end = pagepos_end;
252 
253       return new_idx;
254     }
255     last_idx = new_idx;
256     new_idx = new_idx->next;
257   }
258 
259   // add as last enry
260 
261   new_idx = index_entry_new();
262   new_idx->value = frame;
263   new_idx->pagepos = pagepos;
264   new_idx->pagepos_end = pagepos_end;
265 
266   if (last_idx) {
267     new_idx->prev = last_idx;
268     last_idx->next = new_idx;
269   }
270 
271   return new_idx;
272 }
273 
274 #endif
275 
get_bounds_for(lives_clip_data_t * cdata,int64_t tframe,int64_t * ppos_lower,int64_t * ppos_upper)276 static index_entry *get_bounds_for(lives_clip_data_t *cdata, int64_t tframe, int64_t *ppos_lower, int64_t *ppos_upper) {
277   // find upper and lower pagepos for frame; if we find an exact match, we return it
278   int64_t kframe, frame, gpos;
279 
280   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
281   index_entry *idx = priv->idxc->idx;
282 
283   *ppos_lower = *ppos_upper = -1;
284 
285   while (idx) {
286     if (idx->pagepos < 0) {
287       // kframe was found to be invalid
288       idx = idx->next;
289       continue;
290     }
291 
292     if (priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) {
293       gpos = idx->value;
294       kframe = gpos >> priv->vstream->stpriv->keyframe_granule_shift;
295       frame = kframe + gpos - (kframe << priv->vstream->stpriv->keyframe_granule_shift);
296     } else {
297       kframe = frame = idx->value;
298     }
299 
300     //fprintf(stderr,"check %lld against %lld\n",tframe,kframe);
301 
302     if (kframe > tframe) {
303       *ppos_upper = idx->pagepos;
304       return NULL;
305     }
306 
307     //fprintf(stderr,"2check against %lld\n",frame);
308     if (frame < tframe) {
309       *ppos_lower = idx->pagepos;
310       idx = idx->next;
311       continue;
312     }
313     //fprintf(stderr,"gotit 1\n");
314     return idx;
315   }
316   //fprintf(stderr,"not 1\n");
317   return NULL;
318 }
319 
320 
321 /////////////////////////////////////////////////////
322 
323 #ifdef HAVE_THEORA
ptr_2_op(uint8_t * ptr,ogg_packet * op)324 static uint8_t *ptr_2_op(uint8_t *ptr, ogg_packet *op) {
325   memcpy(op, ptr, sizeof(*op));
326   ptr += sizeof(*op);
327   op->packet = ptr;
328   ptr += op->bytes;
329   return ptr;
330 }
331 #endif
332 
333 
get_page(lives_clip_data_t * cdata,int64_t inpos)334 static int64_t get_page(lives_clip_data_t *cdata, int64_t inpos) {
335   uint8_t header[PAGE_HEADER_BYTES + 255];
336   int nsegs, i;
337   int64_t result, gpos;
338   int page_size;
339   char *buf;
340 
341   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
342   ogg_t *opriv = priv->opriv;
343 
344   if (opriv->page_valid) {
345     fprintf(stderr, "page valid !\n");
346     return 0;
347   }
348 
349   lseek64(opriv->fd, inpos, SEEK_SET);
350 
351   if (read(opriv->fd, header, PAGE_HEADER_BYTES) < PAGE_HEADER_BYTES) {
352     lseek64(opriv->fd, inpos, SEEK_SET);
353     return 0;
354   }
355 
356   nsegs = header[PAGE_HEADER_BYTES - 1];
357 
358   if (read(opriv->fd, header + PAGE_HEADER_BYTES, nsegs) < nsegs) {
359     lseek64(opriv->fd, inpos, SEEK_SET);
360     return 0;
361   }
362 
363   page_size = PAGE_HEADER_BYTES + nsegs;
364 
365   for (i = 0; i < nsegs; i++) page_size += header[PAGE_HEADER_BYTES + i];
366 
367   ogg_sync_reset(&opriv->oy);
368 
369   buf = ogg_sync_buffer(&(opriv->oy), page_size);
370 
371   memcpy(buf, header, PAGE_HEADER_BYTES + nsegs);
372 
373   result = read(opriv->fd, (uint8_t *)buf + PAGE_HEADER_BYTES + nsegs, page_size - PAGE_HEADER_BYTES - nsegs);
374 
375   ogg_sync_wrote(&(opriv->oy), result + PAGE_HEADER_BYTES + nsegs);
376 
377   if (ogg_sync_pageout(&(opriv->oy), &(opriv->current_page)) != 1) {
378     //fprintf(stderr, "Got no packet %lld %d %s\n",result,page_size,buf);
379     return 0;
380   }
381 
382   //fprintf(stderr, "Got packet %lld %d %s\n",result,page_size,buf);
383 
384   if (priv->vstream) {
385     if (priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) {
386       if (ogg_page_serialno(&(opriv->current_page)) == priv->vstream->stream_id) {
387         gpos = ogg_page_granulepos(&(opriv->current_page));
388         pthread_mutex_lock(&priv->idxc->mutex);
389         theora_index_entry_add(cdata, gpos, inpos);
390         pthread_mutex_unlock(&priv->idxc->mutex);
391       }
392     }
393   }
394 
395   opriv->page_valid = 1;
396   return result + PAGE_HEADER_BYTES + nsegs;
397 }
398 
399 
detect_stream(ogg_packet * op)400 static uint32_t detect_stream(ogg_packet *op) {
401   // TODO - do this in the decoder plugins (not in demuxer)
402 
403   //fprintf(stderr,"detecting stream\n");
404   if ((op->bytes > 7) &&
405       (op->packet[0] == 0x01) &&
406       !strncmp((char *)(op->packet + 1), "vorbis", 6)) {
407     //fprintf(stderr,"vorbis found\n");
408     return FOURCC_VORBIS;
409   } else if ((op->bytes > 7) &&
410              (op->packet[0] == 0x80) &&
411              !strncmp((char *)(op->packet + 1), "theora", 6)) {
412     //fprintf(stderr,"theora found\n");
413     return FOURCC_THEORA;
414   } else if ((op->bytes > 5) &&
415              (op->packet[4] == 0x00) &&
416              !strncmp((char *)(op->packet), "BBCD", 4)) {
417     //fprintf(stderr,"dirac found\n");
418     return FOURCC_DIRAC;
419   } else if ((op->bytes > 8) &&
420              (op->packet[8] == 0x00) &&
421              !strncmp((char *)(op->packet), "KW-DIRAC", 8)) {
422     //fprintf(stderr,"dirac found\n");
423     return FOURCC_DIRAC;
424   }
425 
426   return 0;
427 }
428 
429 #define PTR_2_32BE(p) \
430   ((*(p) << 24) | \
431    (*(p+1) << 16) | \
432    (*(p+2) << 8) | \
433    *(p+3))
434 
435 #define PTR_2_32LE(p) \
436   ((*(p+3) << 24) | \
437    (*(p+2) << 16) | \
438    (*(p+1) << 8) | \
439    *(p))
440 
441 
lives_in_stream_new(int type)442 static lives_in_stream *lives_in_stream_new(int type) {
443   lives_in_stream *lstream = (lives_in_stream *)malloc(sizeof(lives_in_stream));
444   lstream->type = type;
445   lstream->ext_data = NULL;
446   lstream->ext_size = 0;
447   return lstream;
448 }
449 
450 
append_extradata(lives_in_stream * s,ogg_packet * op)451 static void append_extradata(lives_in_stream *s, ogg_packet *op) {
452   s->ext_data = realloc(s->ext_data, s->ext_size + sizeof(*op) + op->bytes);
453   memcpy(s->ext_data + s->ext_size, op, sizeof(*op));
454   memcpy(s->ext_data + s->ext_size + sizeof(*op), op->packet, op->bytes);
455   s->ext_size += (sizeof(*op) + op->bytes);
456 }
457 
458 
stream_from_sno(lives_clip_data_t * cdata,int sno)459 static inline lives_in_stream *stream_from_sno(lives_clip_data_t *cdata, int sno) {
460   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
461   if (priv->astream && sno == priv->astream->stream_id) return priv->astream;
462   if (priv->vstream && sno == priv->vstream->stream_id) return priv->vstream;
463   return NULL;
464 }
465 
466 
dirac_uint(bs_t * p_bs)467 static uint32_t dirac_uint(bs_t *p_bs) {
468   uint32_t u_count = 0, u_value = 0;
469 
470   while (!bs_eof(p_bs) && !bs_read(p_bs, 1)) {
471     u_count++;
472     u_value <<= 1;
473     u_value |= bs_read(p_bs, 1);
474   }
475 
476   return (1 << u_count) - 1 + u_value;
477 }
478 
479 
dirac_bool(bs_t * p_bs)480 static int dirac_bool(bs_t *p_bs) {
481   return bs_read(p_bs, 1);
482 }
483 
484 
idxc_for(lives_clip_data_t * cdata)485 static index_container_t *idxc_for(lives_clip_data_t *cdata) {
486   // check all idxc for string match with URI
487   index_container_t *idxc;
488   register int i;
489 
490   pthread_mutex_lock(&indices_mutex);
491 
492   for (i = 0; i < nidxc; i++) {
493     if (indices[i]->clients[0]->current_clip == cdata->current_clip &&
494         !strcmp(indices[i]->clients[0]->URI, cdata->URI)) {
495       idxc = indices[i];
496       // append cdata to clients
497       idxc->clients = (lives_clip_data_t **)realloc(idxc->clients, (idxc->nclients + 1) * sizeof(lives_clip_data_t *));
498       idxc->clients[idxc->nclients] = cdata;
499       idxc->nclients++;
500       //
501       pthread_mutex_unlock(&indices_mutex);
502       return idxc;
503     }
504   }
505 
506   indices = (index_container_t **)realloc(indices, (nidxc + 1) * sizeof(index_container_t *));
507 
508   // match not found, create a new index container
509   idxc = (index_container_t *)malloc(sizeof(index_container_t));
510 
511   idxc->idx = NULL;
512 
513   idxc->nclients = 1;
514   idxc->clients = (lives_clip_data_t **)malloc(sizeof(lives_clip_data_t *));
515   idxc->clients[0] = cdata;
516   pthread_mutex_init(&idxc->mutex, NULL);
517 
518   indices[nidxc] = idxc;
519   pthread_mutex_unlock(&indices_mutex);
520 
521   nidxc++;
522 
523   return idxc;
524 }
525 
526 
idxc_release(lives_clip_data_t * cdata)527 static void idxc_release(lives_clip_data_t *cdata) {
528   lives_ogg_priv_t *priv = cdata->priv;
529   index_container_t *idxc = priv->idxc;
530   register int i, j;
531 
532   if (idxc == NULL) return;
533 
534   pthread_mutex_lock(&indices_mutex);
535 
536   if (idxc->nclients == 1) {
537     // remove this index
538     index_entries_free(idxc->idx);
539     free(idxc->clients);
540     for (i = 0; i < nidxc; i++) {
541       if (indices[i] == idxc) {
542         nidxc--;
543         for (j = i; j < nidxc; j++) {
544           indices[j] = indices[j + 1];
545         }
546         free(idxc);
547         if (nidxc == 0) {
548           free(indices);
549           indices = NULL;
550         } else indices = (index_container_t **)realloc(indices, nidxc * sizeof(index_container_t *));
551         break;
552       }
553     }
554   } else {
555     // reduce client count by 1
556     for (i = 0; i < idxc->nclients; i++) {
557       if (idxc->clients[i] == cdata) {
558         // remove this entry
559         idxc->nclients--;
560         for (j = i; j < idxc->nclients; j++) {
561           idxc->clients[j] = idxc->clients[j + 1];
562         }
563         idxc->clients = (lives_clip_data_t **)realloc(idxc->clients, idxc->nclients * sizeof(lives_clip_data_t *));
564         break;
565       }
566     }
567   }
568 
569   pthread_mutex_unlock(&indices_mutex);
570 }
571 
572 
idxc_release_all(void)573 static void idxc_release_all(void) {
574   register int i;
575 
576   for (i = 0; i < nidxc; i++) {
577     index_entries_free(indices[i]->idx);
578     free(indices[i]->clients);
579     free(indices[i]);
580   }
581   nidxc = 0;
582 }
583 
584 
setup_tracks(lives_clip_data_t * cdata)585 static int setup_tracks(lives_clip_data_t *cdata) {
586   // pull first audio and video streams
587 
588   // some constants for dirac (from vlc)
589   static const struct {
590     uint32_t u_n /* numerator */, u_d /* denominator */;
591   } p_dirac_frate_tbl[] = { /* table 10.3 */
592     {1, 1}, /* this first value is never used */
593     {24000, 1001}, {24, 1}, {25, 1}, {30000, 1001}, {30, 1},
594     {50, 1}, {60000, 1001}, {60, 1}, {15000, 1001}, {25, 2},
595   };
596   static const size_t u_dirac_frate_tbl = sizeof(p_dirac_frate_tbl) / sizeof(*p_dirac_frate_tbl);
597 
598   static const uint32_t pu_dirac_vidfmt_frate[] = { /* table C.1 */
599     1, 9, 10, 9, 10, 9, 10, 4, 3, 7, 6, 4, 3, 7, 6, 2, 2, 7, 6, 7, 6,
600   };
601   static const size_t u_dirac_vidfmt_frate = sizeof(pu_dirac_vidfmt_frate) / sizeof(*pu_dirac_vidfmt_frate);
602 
603   ////////////////////////////////
604 
605   int done;
606   stream_priv_t *ogg_stream;
607   int serialno;
608   int header_bytes = 0;
609   int64_t input_pos;
610 
611   uint8_t imajor, iminor;
612 
613 #ifdef HAVE_THEORA
614   uint8_t isubminor;
615 #endif
616 
617   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
618   ogg_t *opriv = priv->opriv;
619 
620   uint32_t u_video_format, u_n, u_d;
621 
622   bs_t bs;
623 
624   opriv->page_valid = 0;
625 
626   lseek64(opriv->fd, 0, SEEK_SET);
627   priv->input_position = 0;
628 
629   /* Get the first page of each stream */
630   while (1) {
631     if (!(input_pos = get_page(cdata, priv->input_position))) {
632       //fprintf(stderr, "EOF1 while setting up track\n");
633       return 0;
634     }
635 
636     priv->input_position += input_pos;
637 
638     if (!ogg_page_bos(&(opriv->current_page))) {
639       opriv->page_valid = 1;
640       break;
641     }
642 
643     /* Setup stream */
644     serialno = ogg_page_serialno(&(opriv->current_page));
645     ogg_stream = calloc(1, sizeof(*ogg_stream));
646     ogg_stream->last_granulepos = -1;
647 
648     ogg_stream_init(&ogg_stream->os, serialno);
649     ogg_stream_pagein(&ogg_stream->os, &(opriv->current_page));
650     opriv->page_valid = 0;
651     header_bytes += opriv->current_page.header_len + opriv->current_page.body_len;
652 
653     if (ogg_stream_packetout(&ogg_stream->os, &opriv->op) != 1) {
654       fprintf(stderr, "EOF3 while setting up track\n");
655       ogg_stream_clear(&ogg_stream->os);
656       free(ogg_stream);
657       return 0;
658     }
659 
660     // TODO - do stream detection in decoder plugins
661 
662     ogg_stream->fourcc_priv = detect_stream(&opriv->op);
663 
664     switch (ogg_stream->fourcc_priv) {
665     case FOURCC_VORBIS:
666       if (priv->astream != NULL) {
667         fprintf(stderr, "got extra audio stream\n");
668         ogg_stream_clear(&ogg_stream->os);
669         free(ogg_stream);
670         break;
671       }
672       priv->astream = lives_in_stream_new(LIVES_STREAM_AUDIO);
673       priv->astream->fourcc = FOURCC_VORBIS;
674       priv->astream->stpriv   = ogg_stream;
675       priv->astream->stream_id = serialno;
676 
677       ogg_stream->header_packets_needed = 3;
678       append_extradata(priv->astream, &opriv->op);
679       ogg_stream->header_packets_read = 1;
680 
681       /* Get samplerate */
682       priv->astream->samplerate = PTR_2_32LE(opriv->op.packet + 12);
683       //fprintf(stderr,"rate is %d\n",priv->astream->samplerate);
684 
685       /* Read remaining header packets from this page */
686       while (ogg_stream_packetout(&ogg_stream->os, &opriv->op) == 1) {
687         append_extradata(priv->astream, &opriv->op);
688         ogg_stream->header_packets_read++;
689         if (ogg_stream->header_packets_read == ogg_stream->header_packets_needed)  break;
690       }
691       break;
692 #ifdef HAVE_THEORA
693     case FOURCC_THEORA:
694       if (priv->vstream != NULL) {
695         fprintf(stderr, "got extra video stream\n");
696         ogg_stream_clear(&ogg_stream->os);
697         free(ogg_stream);
698         break;
699       }
700       priv->vstream = lives_in_stream_new(LIVES_STREAM_VIDEO);
701       priv->vstream->fourcc = FOURCC_THEORA;
702       priv->vstream->stpriv   = ogg_stream;
703       priv->vstream->stream_id = serialno;
704 
705       ogg_stream->header_packets_needed = 3;
706       append_extradata(priv->vstream, &opriv->op);
707       ogg_stream->header_packets_read = 1;
708 
709       priv->vstream->data_start = 0;
710 
711       /* get version */
712       imajor = ((uint8_t *)(priv->vstream->ext_data))[55];
713       iminor = ((uint8_t *)(priv->vstream->ext_data))[56];
714       isubminor = ((uint8_t *)(priv->vstream->ext_data))[57];
715 
716       priv->vstream->version = imajor * 1000000 + iminor * 1000 + isubminor;
717 
718       // TODO - get frame width, height, picture width, height, and x and y offsets
719 
720       cdata->seek_flag = LIVES_SEEK_FAST | LIVES_SEEK_NEEDS_CALCULATION;
721 
722       /* Get fps and keyframe shift */
723       priv->vstream->fps_num = PTR_2_32BE(opriv->op.packet + 22);
724       priv->vstream->fps_denom = PTR_2_32BE(opriv->op.packet + 26);
725 
726       //fprintf(stderr,"fps is %d / %d\n",priv->vstream->fps_num,priv->vstream->fps_denom);
727 
728       ogg_stream->keyframe_granule_shift = (char)((opriv->op.packet[40] & 0x03) << 3);
729       ogg_stream->keyframe_granule_shift |= (opriv->op.packet[41] & 0xe0) >> 5;
730 
731       /* Read remaining header packets from this page */
732       while (ogg_stream_packetout(&ogg_stream->os, &opriv->op) == 1) {
733         append_extradata(priv->vstream, &opriv->op);
734         ogg_stream->header_packets_read++;
735         if (ogg_stream->header_packets_read == ogg_stream->header_packets_needed) break;
736       }
737 
738       break;
739 #endif
740     case FOURCC_DIRAC:
741       if (priv->vstream != NULL) {
742         fprintf(stderr, "got extra video stream\n");
743         ogg_stream_clear(&ogg_stream->os);
744         free(ogg_stream);
745         break;
746       }
747 
748       priv->vstream = lives_in_stream_new(LIVES_STREAM_VIDEO);
749       priv->vstream->fourcc = FOURCC_DIRAC;
750       priv->vstream->stpriv   = ogg_stream;
751       priv->vstream->stream_id = serialno;
752 
753       priv->vstream->data_start = priv->input_position - input_pos;
754 
755       ogg_stream->header_packets_needed = 0;
756       ogg_stream->header_packets_read = 1;
757 
758       ogg_stream->keyframe_granule_shift = 22; /* not 32 */
759 
760       /* read in useful bits from sequence header */
761       bs_init(&bs, &opriv->op.packet, opriv->op.bytes);
762 
763       /* get version */
764       bs_skip(&bs, 13 * 8); /* parse_info_header */
765 
766       imajor = dirac_uint(&bs); /* major_version */
767       iminor = dirac_uint(&bs); /* minor_version */
768       //iprof=dirac_uint( &bs ); /* profile */
769       //ilevel=dirac_uint( &bs ); /* level */
770 
771       priv->vstream->version = imajor * 1000000 + iminor * 1000;
772 
773       //printf("dirac version %d\n",priv->vstream->version);
774 
775       u_video_format = dirac_uint(&bs);   /* index */
776       if (u_video_format >= u_dirac_vidfmt_frate) {
777         /* don't know how to parse this ogg dirac stream */
778         ogg_stream_clear(&ogg_stream->os);
779         free(ogg_stream);
780         free(priv->vstream);
781         priv->vstream = NULL;
782         break;
783       }
784 
785       if (dirac_bool(&bs)) {
786         cdata->frame_width = cdata->width = dirac_uint(&bs); /* frame_width */
787         cdata->frame_height = cdata->width = dirac_uint(&bs); /* frame_height */
788       }
789       // else...????
790 
791       if (dirac_bool(&bs)) {
792         dirac_uint(&bs);   /* chroma_format */
793       }
794 
795       if (dirac_bool(&bs)) {
796         dirac_uint(&bs);   /* scan_format */
797       }
798 
799       u_n = p_dirac_frate_tbl[pu_dirac_vidfmt_frate[u_video_format]].u_n;
800       u_d = p_dirac_frate_tbl[pu_dirac_vidfmt_frate[u_video_format]].u_d;
801 
802       if (dirac_bool(&bs)) {
803         uint32_t u_frame_rate_index = dirac_uint(&bs);
804         if (u_frame_rate_index >= u_dirac_frate_tbl) {
805           /* something is wrong with this stream */
806           ogg_stream_clear(&ogg_stream->os);
807           free(ogg_stream);
808           free(priv->vstream);
809           priv->vstream = NULL;
810           break;
811         }
812         u_n = p_dirac_frate_tbl[u_frame_rate_index].u_n;
813         u_d = p_dirac_frate_tbl[u_frame_rate_index].u_d;
814         if (u_frame_rate_index == 0) {
815           u_n = dirac_uint(&bs);   /* frame_rate_numerator */
816           u_d = dirac_uint(&bs);   /* frame_rate_denominator */
817         }
818       }
819 
820       cdata->fps = (float) u_n / (float) u_d;
821 
822       cdata->seek_flag = LIVES_SEEK_FAST | LIVES_SEEK_NEEDS_CALCULATION | LIVES_SEEK_QUALITY_LOSS;
823 
824       priv->vstream->fps_num = u_n;
825       priv->vstream->fps_denom = u_d;
826 
827       break;
828 
829     default:
830       ogg_stream_clear(&ogg_stream->os);
831       free(ogg_stream);
832       break;
833     }
834   }
835 
836   if (priv->vstream == NULL) return 0;
837 
838   /*
839       Now, read header pages until we are done, current_page still contains the
840       first page which has no bos marker set
841   */
842 
843   done = 0;
844   while (!done) {
845     lives_in_stream *stream = stream_from_sno(cdata, ogg_page_serialno(&(opriv->current_page)));
846     if (stream) {
847       ogg_stream = (stream_priv_t *)(stream->stpriv);
848       ogg_stream_pagein(&(ogg_stream->os), &(opriv->current_page));
849       opriv->page_valid = 0;
850       header_bytes += opriv->current_page.header_len + opriv->current_page.body_len;
851 
852       switch (ogg_stream->fourcc_priv) {
853       case FOURCC_THEORA:
854       case FOURCC_VORBIS:
855         /* Read remaining header packets from this page */
856         while (ogg_stream_packetout(&ogg_stream->os, &opriv->op) == 1) {
857           append_extradata(stream, &opriv->op);
858           ogg_stream->header_packets_read++;
859           /* Second packet is vorbis comment starting after 7 bytes */
860           //if (ogg_stream->header_packets_read == 2) parse_vorbis_comment(stream, opriv->op.packet + 7, opriv->op.bytes - 7);
861           if (ogg_stream->header_packets_read == ogg_stream->header_packets_needed) break;
862         }
863         break;
864       }
865     } else {
866       opriv->page_valid = 0;
867       header_bytes += opriv->current_page.header_len + opriv->current_page.body_len;
868     }
869 
870     /* Check if we are done for all streams */
871     done = 1;
872 
873     //for (i = 0; i < track->num_audio_streams; i++) {
874     if (priv->astream != NULL) {
875       ogg_stream = priv->astream->stpriv;
876       if (ogg_stream->header_packets_read < ogg_stream->header_packets_needed) done = 0;
877     }
878 
879     if (done) {
880       //for(i = 0; i < track->num_video_streams; i++)
881       //{
882       if (priv->vstream != NULL) {
883         ogg_stream = priv->vstream->stpriv;
884         if (ogg_stream->header_packets_read < ogg_stream->header_packets_needed) done = 0;
885       }
886     }
887     //}
888 
889     /* Read the next page if we aren't done yet */
890 
891     if (!done) {
892       if (!(input_pos = get_page(cdata, priv->input_position))) {
893         fprintf(stderr, "EOF2 while setting up track");
894         return 0;
895       }
896       priv->input_position += input_pos;
897     }
898   }
899 
900   if (priv->vstream->data_start == 0) priv->vstream->data_start = priv->input_position;
901 
902   return 1;
903 }
904 
905 
906 #ifdef HAVE_DIRAC
get_dirac_cdata(lives_clip_data_t * cdata,SchroDecoder * schrodec)907 void get_dirac_cdata(lives_clip_data_t *cdata, SchroDecoder *schrodec) {
908   SchroVideoFormat *sformat = schro_decoder_get_video_format(schrodec);
909   cdata->frame_width = sformat->width;
910   cdata->frame_height = sformat->height;
911 
912   cdata->width = sformat->clean_width;
913   cdata->height = (sformat->clean_height >> 1) << 1;
914 
915   if (sformat->interlaced) {
916     if (sformat->top_field_first) cdata->interlace = LIVES_INTERLACE_TOP_FIRST;
917     else cdata->interlace = LIVES_INTERLACE_BOTTOM_FIRST;
918   } else cdata->interlace = LIVES_INTERLACE_NONE;
919 
920   switch (sformat->chroma_format) {
921   case SCHRO_CHROMA_420:
922     cdata->palettes[0] = WEED_PALETTE_YUV420P;
923     break;
924   case SCHRO_CHROMA_422:
925     cdata->palettes[0] = WEED_PALETTE_YUV422P;
926     break;
927   case SCHRO_CHROMA_444:
928     cdata->palettes[0] = WEED_PALETTE_YUV444P;
929     break;
930   default:
931     cdata->palettes[0] = WEED_PALETTE_END;
932     break;
933   }
934 
935   //if (sformat->colour_matrix==SCHRO_COLOUR_MATRIX_HDTV) cdata->YUV_subspace=WEED_YUV_SUBSPACE_BT709;
936 
937   cdata->offs_x = sformat->left_offset;
938   cdata->offs_y = sformat->top_offset;
939 
940   cdata->par = sformat->aspect_ratio_numerator / sformat->aspect_ratio_denominator;
941 
942   if (sformat->luma_offset == 0) cdata->YUV_clamping = WEED_YUV_CLAMPING_UNCLAMPED;
943   else cdata->YUV_clamping = WEED_YUV_CLAMPING_CLAMPED;
944 
945   //printf("vals %d %d %d %d %d %d\n",sformat->width,sformat->height,sformat->clean_width,sformat->clean_height,sformat->interlaced,cdata->palettes[0]);
946 
947   free(sformat);
948 }
949 #endif
950 
951 
seek_byte(lives_clip_data_t * cdata,int64_t pos)952 static void seek_byte(lives_clip_data_t *cdata, int64_t pos) {
953   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
954   ogg_t *opriv = priv->opriv;
955 
956   ogg_sync_reset(&(opriv->oy));
957   lseek64(opriv->fd, pos, SEEK_SET);
958   priv->input_position = pos;
959   opriv->page_valid = 0;
960 }
961 
962 
963 /* Get new data */
964 
get_data(lives_clip_data_t * cdata,size_t bytes_to_read)965 static int64_t get_data(lives_clip_data_t *cdata, size_t bytes_to_read) {
966   char *buf;
967   int64_t result;
968 
969   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
970   ogg_t *opriv = priv->opriv;
971 
972   if (opriv->total_bytes > 0) {
973     if (priv->input_position + bytes_to_read > opriv->total_bytes)
974       bytes_to_read = opriv->total_bytes - priv->input_position;
975     if (bytes_to_read <= 0)
976       return 0;
977   }
978 
979   ogg_sync_reset(&opriv->oy);
980   buf = ogg_sync_buffer(&(opriv->oy), bytes_to_read);
981 
982   lseek64(opriv->fd, priv->input_position, SEEK_SET);
983   result = read(opriv->fd, (uint8_t *)buf, bytes_to_read);
984 
985   opriv->page_valid = 0;
986 
987   ogg_sync_wrote(&(opriv->oy), result);
988   return result;
989 }
990 
991 
992 /* Find the first first page between pos1 and pos2,
993    return file position, -1 is returned on failure. For theora only. */
994 
find_first_page(lives_clip_data_t * cdata,int64_t pos1,int64_t pos2,int64_t * kframe,int64_t * frame)995 static int64_t find_first_page(lives_clip_data_t *cdata, int64_t pos1, int64_t pos2, int64_t *kframe, int64_t *frame) {
996   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
997 
998   int64_t bytes;
999   long result;
1000 
1001   ogg_t *opriv = priv->opriv;
1002 
1003   int pages_checked = 0, page_packets_checked;
1004 
1005   size_t bytes_to_read = pos2 - pos1 + 1;
1006 
1007   int64_t granulepos;
1008 
1009   // check index to see if pos1 is in index
1010 
1011   // pull pages and check packets until we either reach the end or find a granulepos
1012 
1013   priv->input_position = pos1;
1014 
1015   //printf ("start %ld %ld\n",pos1,pos2);
1016 
1017   seek_byte(cdata, pos1);
1018 
1019   if (pos1 == priv->vstream->data_start) {
1020     /* set a dummy granulepos at data_start */
1021     *kframe = priv->kframe_offset;
1022     *frame = priv->kframe_offset;
1023 
1024     opriv->page_valid = 1;
1025     return priv->input_position;
1026   }
1027 
1028   if (bytes_to_read > BYTES_TO_READ) bytes_to_read = BYTES_TO_READ;
1029 
1030   while (1) {
1031     if (priv->input_position >= pos2) {
1032       // we reached the end and found no pages
1033       //printf("exit a\n");
1034       *frame = -1;
1035       return -1;
1036     }
1037 
1038     // read next chunk
1039     if (!(bytes = get_data(cdata, bytes_to_read))) {
1040       //printf("exit b\n");
1041       *frame = -1;
1042       return -1; // eof
1043     }
1044 
1045     bytes_to_read = BYTES_TO_READ;
1046 
1047     result = ogg_sync_pageseek(&opriv->oy, &opriv->current_page);
1048 
1049     //printf("result is %ld\n",result);
1050 
1051     if (result < 0) {
1052       // found a page, sync to page start
1053       priv->input_position -= result;
1054       pos1 = priv->input_position;
1055       continue;
1056     }
1057 
1058     if (result > 0 || (result == 0 && opriv->oy.fill > 3 && !strncmp((char *)opriv->oy.data, "OggS", 4))) {
1059       pos1 = priv->input_position;
1060       break;
1061     }
1062 
1063     priv->input_position += bytes;
1064   }
1065 
1066   seek_byte(cdata, priv->input_position);
1067   ogg_stream_reset(&priv->vstream->stpriv->os);
1068 
1069   while (1) {
1070     //printf("here %ld and %ld\n",priv->input_position,pos2);
1071 
1072     if (priv->input_position >= pos2) {
1073       // reached the end of the search region and nothing was found
1074       *frame = -1;
1075       return priv->input_position; // we checked up to here
1076     }
1077 
1078     //printf("a: checking page\n");
1079 
1080     opriv->page_valid = 0;
1081 
1082     if (!(result = get_page(cdata, priv->input_position))) {
1083       // EOF
1084       //printf("EOF ?\n");
1085       *frame = -1;
1086       return priv->input_position; // we checked up to here
1087     }
1088 
1089     // found a page
1090     if (priv->vstream->stream_id != ogg_page_serialno(&(opriv->current_page))) {
1091       // page is not for this stream
1092       //printf("not for us\n");
1093       priv->input_position += result;
1094       if (!pages_checked) pos1 = priv->input_position;
1095       continue;
1096     }
1097 
1098     ogg_stream_pagein(&priv->vstream->stpriv->os, &(opriv->current_page));
1099 
1100     pages_checked++;
1101 
1102     page_packets_checked = 0;
1103 
1104     if (ogg_stream_packetout(&priv->vstream->stpriv->os, &opriv->op) > 0) {
1105       page_packets_checked++;
1106     }
1107 
1108     if (page_packets_checked) {
1109       granulepos = ogg_page_granulepos(&(opriv->current_page));
1110       pthread_mutex_lock(&priv->idxc->mutex);
1111       theora_index_entry_add(cdata, granulepos, pos1);
1112       pthread_mutex_unlock(&priv->idxc->mutex);
1113 
1114       *kframe =
1115         granulepos >> priv->vstream->stpriv->keyframe_granule_shift;
1116 
1117       *frame = *kframe +
1118                granulepos - (*kframe << priv->vstream->stpriv->keyframe_granule_shift);
1119 
1120       opriv->page_valid = 1;
1121       return pos1;
1122     }
1123 
1124     //  -> start of next page
1125     priv->input_position += result;
1126   }
1127 }
1128 
1129 
1130 /* Find the last frame for theora,
1131    -1 is returned on failure */
1132 
find_last_theora_frame(lives_clip_data_t * cdata,lives_in_stream * vstream)1133 static int64_t find_last_theora_frame(lives_clip_data_t *cdata, lives_in_stream *vstream) {
1134   int64_t page_pos, start_pos;
1135   int64_t this_frame = 0, last_frame = -1;
1136   int64_t this_kframe = 0;
1137   int64_t pos1, pos2;
1138 
1139   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
1140   ogg_t *opriv = priv->opriv;
1141 
1142   pos1 = vstream->data_start;
1143   pos2 = opriv->total_bytes;
1144   //serialno=vstream->stream_id;
1145 
1146   start_pos = pos2 - BYTES_TO_READ;
1147 
1148   while (1) {
1149     if (start_pos < pos1) start_pos = pos1;
1150 
1151     //printf("in pos %ld and %ld with %ld\n",start_pos,pos2,vstream->data_start);
1152 
1153     page_pos = find_first_page(cdata, start_pos, pos2, &this_kframe, &this_frame);
1154 
1155     //printf("found page %ld %ld %ld\n",this_frame,last_frame,page_pos);
1156 
1157     if (this_frame == -1) {
1158       // no pages found in range
1159       if (last_frame >= 0) {     /* No more pages in range -> return last one */
1160         return last_frame;
1161       }
1162       if (start_pos <= pos1) {
1163         return -1;
1164       }
1165       /* Go back a bit */
1166       pos2 -= start_pos;
1167       start_pos -= BYTES_TO_READ;
1168       if (start_pos < pos1) start_pos = pos1;
1169       pos2 += start_pos;
1170     } else {
1171       // found a page, see if we can find another one
1172       //printf("set last_frame to %ld\n",this_frame);
1173       last_frame = this_frame;
1174       start_pos = page_pos + 1;
1175     }
1176   }
1177   return -1;
1178 }
1179 
1180 
1181 #ifdef HAVE_DIRAC
1182 
1183 /* find first sync frame in a given file region. Return file offset. -1 is returned if no sync frame found.
1184    pos2 in not included in the search.
1185    This is for dirac only. */
1186 
find_first_sync_frame(lives_clip_data_t * cdata,int64_t pos1,int64_t pos2,int64_t * frame)1187 static int64_t find_first_sync_frame(lives_clip_data_t *cdata, int64_t pos1, int64_t pos2, int64_t *frame) {
1188   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
1189 
1190   index_entry *idx = priv->idxc->idx;
1191   index_entry *extend = NULL;
1192 
1193   int64_t bytes;
1194   long result;
1195 
1196   ogg_t *opriv = priv->opriv;
1197   dirac_priv_t *dpriv = priv->dpriv;
1198 
1199   int pages_checked = 0, page_packets_checked;
1200 
1201   size_t bytes_to_read = pos2 - pos1 + 1;
1202 
1203   // check index to see if pos1 is in index
1204 
1205   while (idx != NULL) {
1206     if (idx->pagepos == pos1 && idx->value > -1) {
1207       // found !
1208       *frame = idx->value;
1209       return pos1;
1210     }
1211 
1212     if (idx->pagepos < pos1 && idx->pagepos_end > pos1) {
1213 
1214       // region was partly checked
1215       // continue from pagepos_end + 1
1216       pos1 = idx->pagepos_end + 1;
1217 
1218       if (idx->pagepos_end >= pos2 - 1) {
1219         // region was checked and there are no seq frames
1220         *frame = -1;
1221         return pos1;
1222       }
1223 
1224       break;
1225     }
1226 
1227     if (idx->pagepos >= pos2) {
1228       // no entry found
1229       break;
1230     }
1231 
1232     idx = idx->next;
1233   }
1234 
1235   // pull pages and check packets until we either reach the end or find a sync point
1236 
1237   priv->input_position = pos1;
1238 
1239   ogg_stream_reset(&priv->vstream->stpriv->os);
1240 
1241   //printf ("start %ld %ld\n",pos1,pos2);
1242 
1243   seek_byte(cdata, pos1);
1244 
1245   if (bytes_to_read > BYTES_TO_READ) bytes_to_read = BYTES_TO_READ;
1246 
1247   while (1) {
1248     if (priv->input_position >= pos2) {
1249       // we reached the end and found no pages
1250       //printf("exit a\n");
1251       *frame = -1;
1252       return -1;
1253     }
1254 
1255     // read next chunk
1256     if (!(bytes = get_data(cdata, bytes_to_read))) {
1257       //printf("exit b\n");
1258       *frame = -1;
1259       return -1; // eof
1260     }
1261 
1262     bytes_to_read = BYTES_TO_READ;
1263 
1264     result = ogg_sync_pageseek(&opriv->oy, &opriv->current_page);
1265 
1266     //printf("result is %ld\n",result);
1267 
1268     if (result < 0) {
1269       // found a page, sync to page start
1270       priv->input_position -= result;
1271       pos1 = priv->input_position;
1272       continue;
1273     }
1274 
1275     if (result > 0 || (result == 0 && opriv->oy.fill > 3 && !strncmp((char *)opriv->oy.data, "OggS", 4))) {
1276       pos1 = priv->input_position;
1277       break;
1278     }
1279 
1280     priv->input_position += bytes;
1281   }
1282 
1283   seek_byte(cdata, priv->input_position);
1284   ogg_stream_reset(&priv->vstream->stpriv->os);
1285 
1286   while (1) {
1287     //printf("here %ld and %ld\n",priv->input_position,pos2);
1288 
1289     if (priv->input_position >= pos2) {
1290       //printf("exit 1 %ld %ld %ld\n",priv->input_position,result,pos2);
1291       // reached the end of the search region and nothing was found
1292       *frame = -1;
1293       return priv->input_position; // we checked up to here
1294     }
1295 
1296     pthread_mutex_lock(&priv->idxc->mutex);
1297 
1298     if ((idx = find_pagepos_in_index(priv->idxc->idx, priv->input_position)) != NULL) {
1299       // this part was already checked
1300 
1301       //printf("WE ALREADY CHECKED THIS\n");
1302 
1303       if (idx->value != -1) {
1304         // we already found a sync frame here
1305         if (extend != NULL) {
1306           extend->pagepos_end = idx->pagepos - 1;
1307           if (extend->pagepos_end < extend->pagepos) priv->idxc->idx = index_entry_delete(extend);
1308         }
1309 
1310         *frame = idx->value;
1311         pthread_mutex_unlock(&priv->idxc->mutex);
1312         //printf("As I recall, the sync frame was %ld\n",*frame);
1313         return idx->pagepos;
1314       }
1315 
1316       // no sync frame here - update this entry and jump to pagepos_end
1317       if (pages_checked >= 2 && idx->pagepos < pos1) idx->pagepos = pos1;
1318 
1319       pos1 = priv->input_position = idx->pagepos_end + 1;
1320       pthread_mutex_unlock(&priv->idxc->mutex);
1321 
1322       //printf("no seq frames, skipping\n");
1323 
1324       // need more data
1325       ogg_stream_reset(&priv->vstream->stpriv->os);
1326 
1327       continue;
1328     }
1329 
1330     //printf("a: checking page\n");
1331 
1332     opriv->page_valid = 0;
1333 
1334     if (!(result = get_page(cdata, priv->input_position))) {
1335       // EOF
1336       //printf("EOF ?\n");
1337       *frame = -1;
1338       return priv->input_position; // we checked up to here
1339     }
1340 
1341     // found a page
1342     if (priv->vstream->stream_id != ogg_page_serialno(&(opriv->current_page))) {
1343       // page is not for this stream
1344       //printf("not for us\n");
1345       priv->input_position += result;
1346       if (!pages_checked) pos1 = priv->input_position;
1347       continue;
1348     }
1349 
1350     ogg_stream_pagein(&priv->vstream->stpriv->os, &(opriv->current_page));
1351 
1352     if (pages_checked > 0) pages_checked++;
1353 
1354     page_packets_checked = 0;
1355 
1356     while (ogg_stream_packetout(&priv->vstream->stpriv->os, &opriv->op) > 0) {
1357       //printf("a checking packet %c %c %c %c %d\n",opriv->op.packet[0],opriv->op.packet[1],opriv->op.packet[2],opriv->op.packet[3],opriv->op.packet[4]);
1358 
1359       page_packets_checked++;
1360 
1361       // is this packet a seq start ?
1362       if (opriv->op.packet[4] == 0) {
1363         //printf("got a seq start\n");
1364 
1365         // if other packets ended on this page, we know that seq start begins on this page
1366         // otherwise it will have begun at pos1
1367         if (page_packets_checked > 1) pos1 = priv->input_position;
1368 
1369         // get the frame number, close extend, add a new index entry
1370         seek_byte(cdata, pos1);
1371 
1372         // feed packets to the dirac_decoder until we get a frame number
1373         // note: in theory we should be able to get the next frame from the granulepos
1374         // however this seems broken
1375         priv->last_frame = -1;
1376         priv->cframe = -1;
1377 
1378         ogg_data_process(cdata, NULL, FALSE);
1379 
1380         //printf("seq frame was %ld\n",priv->last_frame);
1381 
1382         *frame = priv->last_frame;
1383 
1384         schro_decoder_reset(dpriv->schrodec);
1385 
1386         ogg_stream_reset(&priv->vstream->stpriv->os);
1387 
1388         pthread_mutex_lock(&priv->idxc->mutex);
1389         if (priv->last_frame > -1) {
1390           // finish off the previous search area
1391           if (extend) {
1392             extend->pagepos_end = pos1 - 1;
1393             if (extend->pagepos_end < extend->pagepos) priv->idxc->idx = index_entry_delete(extend);
1394           }
1395 
1396           // and add this one
1397           extend = dirac_index_entry_add(cdata, pos1, priv->input_position + result - 1, *frame);
1398 
1399           if (extend->pagepos_end < extend->pagepos) priv->idxc->idx = index_entry_delete(extend);
1400           else if (!extend->prev) priv->idxc->idx = extend;
1401 
1402         } else {
1403           // we got no frames, we must have reached EOF
1404           if (extend) {
1405             extend->pagepos_end = priv->input_position - 1;
1406             if (extend->pagepos_end < extend->pagepos) priv->idxc->idx = index_entry_delete(extend);
1407           }
1408           pos1 = -1;
1409         }
1410         pthread_mutex_unlock(&priv->idxc->mutex);
1411 
1412         return pos1; // return offset of start page
1413       }
1414     }
1415 
1416     if (page_packets_checked > 0) {
1417       // we got some other kind of packet out, so a sequence header packet could only begin on this page
1418       pos1 = priv->input_position; // the start of this page
1419 
1420       if (pages_checked == -1) {
1421         // we can start counting pages from here
1422         pages_checked = 1;
1423       }
1424 
1425       if (pages_checked >= 2) {
1426         // if we checked from one packet to the next and found no seq header.
1427         // We now know that the first pages had no seq header
1428         // so we can start marking from pos1 up to start of this page - 1
1429         pthread_mutex_lock(&priv->idxc->mutex);
1430         if (!extend) {
1431           extend = dirac_index_entry_add(cdata, pos1, priv->input_position - 1, -1);
1432           if (!extend->prev) priv->idxc->idx = extend;
1433         } else {
1434           extend->pagepos_end = priv->input_position - 1;
1435         }
1436         if (extend->pagepos_end < extend->pagepos) priv->idxc->idx = index_entry_delete(extend);
1437         else if (extend->prev && extend->prev->pagepos_end == extend->pagepos - 1 && extend->prev->value == -1) {
1438           extend->prev->pagepos_end = extend->pagepos_end;
1439           index_entry_delete(extend);
1440         }
1441         pthread_mutex_unlock(&priv->idxc->mutex);
1442       }
1443     }
1444 
1445     //  -> start of next page
1446     priv->input_position += result;
1447   }
1448 }
1449 
1450 
1451 /* find last sync frame position in a given file region. Return file offset. -1 is returned if no sync frame found.
1452   This is for dirac only. */
1453 
find_last_sync_frame(lives_clip_data_t * cdata,lives_in_stream * vstream)1454 static int64_t find_last_sync_frame(lives_clip_data_t *cdata, lives_in_stream *vstream) {
1455   int64_t page_pos, last_page_pos = -1, start_pos;
1456   int64_t this_frame = -1;
1457   int64_t pos1, pos2;
1458 
1459   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
1460   ogg_t *opriv = priv->opriv;
1461 
1462   pos1 = vstream->data_start;
1463   pos2 = opriv->total_bytes;
1464   //serialno=vstream->stream_id;
1465 
1466   start_pos = pos2 - BYTES_TO_READ;
1467 
1468   while (1) {
1469     if (start_pos < pos1) start_pos = pos1;
1470 
1471     page_pos = find_first_sync_frame(cdata, start_pos, pos2, &this_frame);
1472 
1473     //printf("b found sync at %ld %ld\n",this_frame,page_pos);
1474 
1475     if (this_frame == -1) {
1476       // no sync frames found in range
1477       if (last_page_pos >= 0) {   /* No more pages in range -> return last one */
1478         return last_page_pos;
1479       }
1480       if (start_pos <= pos1) {
1481         return -1;
1482       }
1483       /* Go back a bit */
1484       pos2 -= start_pos;
1485       start_pos -= BYTES_TO_READ;
1486       if (start_pos < pos1) start_pos = pos1;
1487       pos2 += start_pos;
1488     } else {
1489       // found a page, see if we can find another one
1490       last_page_pos = page_pos;
1491       start_pos = page_pos + 1;
1492     }
1493   }
1494   return -1;
1495 }
1496 
1497 #endif
1498 
1499 
get_last_granulepos(lives_clip_data_t * cdata,int serialno)1500 static int64_t get_last_granulepos(lives_clip_data_t *cdata, int serialno) {
1501   // granulepos here is actually a frame - TODO ** fix for audio !
1502 
1503 #ifdef HAVE_DIRAC
1504   int64_t pos;
1505 #endif
1506   lives_in_stream *stream;
1507 
1508   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
1509 
1510   int64_t frame;
1511 
1512   stream = stream_from_sno(cdata, serialno);
1513   if (!stream) return -1;
1514 
1515 #ifdef HAVE_DIRAC
1516   if (stream->stpriv->fourcc_priv == FOURCC_DIRAC) {
1517     dirac_priv_t *dpriv = priv->dpriv;
1518 
1519     pos = find_last_sync_frame(cdata, priv->vstream);
1520     seek_byte(cdata, pos);
1521 
1522     ogg_stream_reset(&priv->vstream->stpriv->os);
1523 
1524     schro_decoder_reset(dpriv->schrodec);
1525 
1526     priv->last_frame = -1;
1527     priv->cframe = -1;
1528 
1529     ogg_data_process(cdata, NULL, FALSE); // read pages from last sync frame
1530 
1531     while (ogg_data_process(cdata, NULL, TRUE)); // continue until we reach EOF
1532 
1533     schro_decoder_reset(dpriv->schrodec);
1534 
1535     ogg_stream_reset(&priv->vstream->stpriv->os);
1536 
1537     //printf("last dirac frame is %ld, adjust to %ld\n",priv->last_frame, priv->last_frame-priv->kframe_offset);
1538 
1539     priv->last_frame -= priv->kframe_offset;
1540 
1541     return priv->last_frame;
1542   }
1543 #endif
1544 
1545   // TODO - fix for vorbis
1546 
1547   frame = find_last_theora_frame(cdata, priv->vstream);
1548   if (frame < 0) return -1;
1549 
1550   return frame;
1551 }
1552 
1553 
granulepos_2_time(lives_in_stream * s,int64_t pos)1554 static double granulepos_2_time(lives_in_stream *s, int64_t pos) {
1555   // actually should be frame or sample to time
1556 
1557   int64_t frames;
1558   stream_priv_t *stream_priv = (stream_priv_t *)(s->stpriv);
1559 
1560   switch (stream_priv->fourcc_priv) {
1561   case FOURCC_VORBIS:
1562     //fprintf(stderr,"apos is %lld\n",pos);
1563     return ((long double)pos / (long double)s->samplerate);
1564     break;
1565   case FOURCC_THEORA:
1566   case FOURCC_DIRAC:
1567     //fprintf(stderr,"vpos is %lld\n",pos);
1568     stream_priv = (stream_priv_t *)(s->stpriv);
1569 
1570     frames = pos;
1571 
1572     return ((double)s->fps_denom / (double)s->fps_num * (double)frames);
1573     break;
1574   }
1575   return -1;
1576 }
1577 
1578 
stream_peek(int fd,char * str,size_t len)1579 static ssize_t stream_peek(int fd, char *str, size_t len) {
1580   off_t cpos = lseek(fd, 0, SEEK_CUR); // get current posn
1581 
1582 #ifndef IS_MINGW
1583   return pread(fd, str, len, cpos); // read len bytes without changing cpos
1584 #else
1585   ssize_t ret = read(fd, str, len);
1586   lseek(fd, cpos, SEEK_SET);
1587   return ret;
1588 #endif
1589 }
1590 
1591 
open_ogg(lives_clip_data_t * cdata)1592 static int open_ogg(lives_clip_data_t *cdata) {
1593   char scheck[4];
1594 
1595   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
1596   ogg_t *opriv = priv->opriv;
1597 
1598   if (stream_peek(opriv->fd, scheck, 4) < 4) return 0;
1599 
1600   if (strncmp(scheck, "OggS", 4)) return 0;
1601 
1602   ogg_sync_init(&(opriv->oy));
1603 
1604   /* Set up the tracks */
1605   if (!setup_tracks(cdata)) {
1606     ogg_sync_clear(&opriv->oy);
1607     return 0;
1608   }
1609 
1610   return 1;
1611 }
1612 
1613 
attach_stream(lives_clip_data_t * cdata,boolean isclone)1614 static boolean attach_stream(lives_clip_data_t *cdata, boolean isclone) {
1615   // open the file and get a handle
1616 
1617   struct stat sb;
1618 
1619   int64_t gpos;
1620 
1621   double stream_duration;
1622 
1623   boolean is_partial_clone = FALSE;
1624 
1625   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
1626   ogg_t *opriv = priv->opriv = (ogg_t *)malloc(sizeof(ogg_t));
1627 
1628   register int i;
1629 
1630   if ((opriv->fd = open(cdata->URI, O_RDONLY)) == -1) {
1631     fprintf(stderr, "ogg_theora_decoder: unable to open %s\n", cdata->URI);
1632     free(opriv);
1633     priv->opriv = NULL;
1634     return FALSE;
1635   }
1636 
1637 #ifdef IS_MINGW
1638   setmode(opriv->fd, O_BINARY);
1639 #endif
1640 
1641   if (isclone && !priv->inited) {
1642     isclone = FALSE;
1643     if (cdata->fps > 0. && cdata->nframes > 0)
1644       is_partial_clone = TRUE;
1645   }
1646 
1647   if (!isclone) {
1648     stat(cdata->URI, &sb);
1649     opriv->total_bytes = sb.st_size;
1650   }
1651 
1652   opriv->page_valid = 0;
1653 
1654   // index init
1655   priv->idxc = idxc_for(cdata);
1656 
1657   /* get ogg info */
1658   if (!open_ogg(cdata)) {
1659     close(opriv->fd);
1660     free(opriv);
1661     priv->opriv = NULL;
1662     return FALSE;
1663   }
1664 
1665   priv->last_kframe = 10000000;
1666   priv->last_frame = 100000000;
1667   priv->inited = TRUE;
1668 
1669 #ifdef HAVE_THEORA
1670   if (priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) {
1671     // theora only
1672     int i;
1673     ogg_packet op;
1674     uint8_t *ext_pos;
1675     theora_priv_t *tpriv = priv->tpriv = (theora_priv_t *)malloc(sizeof(theora_priv_t));
1676 
1677     /* Initialize theora structures */
1678     theora_info_init(&tpriv->ti);
1679     theora_comment_init(&tpriv->tc);
1680 
1681     /* Get header packets and initialize decoder */
1682     if (priv->vstream->ext_data == NULL) {
1683       fprintf(stderr, "Theora codec requires extra data\n");
1684       close(opriv->fd);
1685       free(opriv);
1686       priv->opriv = NULL;
1687       free(tpriv);
1688       priv->tpriv = NULL;
1689       return FALSE;
1690     }
1691 
1692     ext_pos = priv->vstream->ext_data;
1693 
1694     for (i = 0; i < 3; i++) {
1695       ext_pos = ptr_2_op(ext_pos, &op);
1696       theora_decode_header(&tpriv->ti, &tpriv->tc, &op);
1697     }
1698 
1699     theora_decode_init(&tpriv->ts, &tpriv->ti);
1700 
1701     // check to find whether first frame is zero or one
1702     // if version >= 3.2.1 first kframe is 1; otherwise 0
1703     if (priv->vstream->version >= 3002001) priv->kframe_offset = 1;
1704     else priv->kframe_offset = 0;
1705   }
1706 #endif
1707 
1708 #ifdef HAVE_DIRAC
1709   if (priv->vstream->stpriv->fourcc_priv == FOURCC_DIRAC) {
1710     // dirac only
1711     dirac_priv_t *dpriv = priv->dpriv = (dirac_priv_t *)malloc(sizeof(dirac_priv_t));
1712 
1713     schro_init();
1714 
1715     dpriv->schroframe = NULL;
1716 
1717     if ((dpriv->schrodec = schro_decoder_new()) == NULL) {
1718       fprintf(stderr, "Failed to init schro decoder\n");
1719       close(opriv->fd);
1720       free(opriv);
1721       priv->opriv = NULL;
1722       free(dpriv);
1723       priv->dpriv = NULL;
1724       return FALSE;
1725     }
1726     //schro_debug_set_level(SCHRO_LEVEL_WARNING);
1727     schro_debug_set_level(0);
1728   }
1729 #endif
1730 
1731   if (isclone) return TRUE;
1732 
1733   cdata->nclips = 1;
1734 
1735   // video part
1736   cdata->interlace = LIVES_INTERLACE_NONE;
1737 
1738   cdata->par = 1.;
1739 
1740   // TODO
1741   cdata->offs_x = 0;
1742   cdata->offs_y = 0;
1743   cdata->frame_gamma = WEED_GAMMA_UNKNOWN;
1744   cdata->frame_width = cdata->width;
1745   cdata->frame_height = cdata->height;
1746 
1747   cdata->YUV_clamping = WEED_YUV_CLAMPING_CLAMPED;
1748   cdata->YUV_subspace = WEED_YUV_SUBSPACE_YCBCR;
1749   cdata->YUV_sampling = WEED_YUV_SAMPLING_DEFAULT;
1750 
1751   /* Get format */
1752 
1753 #ifdef HAVE_THEORA
1754   if (priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) {
1755     theora_priv_t *tpriv = priv->tpriv;
1756     cdata->width  = cdata->frame_width = opriv->y_width = tpriv->ti.frame_width;
1757     cdata->height = cdata->frame_height = opriv->y_height = tpriv->ti.frame_height;
1758 
1759     if (cdata->fps == 0.) cdata->fps  = (float)tpriv->ti.fps_numerator / (float)tpriv->ti.fps_denominator;
1760 
1761     switch (tpriv->ti.pixelformat) {
1762     case OC_PF_420:
1763       cdata->palettes[0] = WEED_PALETTE_YUV420P;
1764       opriv->uv_width = opriv->y_width >> 1;
1765       break;
1766     case OC_PF_422:
1767       cdata->palettes[0] = WEED_PALETTE_YUV422P;
1768       opriv->uv_width = opriv->y_width >> 1;
1769       break;
1770     case OC_PF_444:
1771       cdata->palettes[0] = WEED_PALETTE_YUV444P;
1772       opriv->uv_width = opriv->y_width;
1773       break;
1774     default:
1775       fprintf(stderr, "Unknown pixelformat %d", tpriv->ti.pixelformat);
1776       return FALSE;
1777     }
1778 
1779     cdata->palettes[1] = WEED_PALETTE_END;
1780     cdata->current_palette = cdata->palettes[0];
1781     sprintf(cdata->video_name, "%s", "theora");
1782 
1783     if (tpriv->tc.comments > 0) {
1784       size_t lenleft = 256, csize;
1785       char *cbuf = cdata->comment;
1786       for (i = 0; i <= tpriv->tc.comments; i++) {
1787         csize = tpriv->tc.comment_lengths[i];
1788         if (csize > lenleft) csize = lenleft;
1789         snprintf(cbuf, csize, "%s", tpriv->tc.user_comments[i]);
1790         cbuf += csize;
1791         lenleft -= csize;
1792         if (lenleft == 0) break;
1793         if (i + 1 <= tpriv->tc.comments) {
1794           if (lenleft < strlen("\n") + 1) break;
1795           sprintf(cbuf, "\n");
1796           cbuf += strlen("\n");
1797           lenleft -= strlen("\n");
1798         }
1799       }
1800     }
1801 
1802   }
1803 #endif
1804 
1805 #ifdef HAVE_DIRAC
1806   if (priv->vstream->stpriv->fourcc_priv == FOURCC_DIRAC) {
1807     // feed some pages to the decoder so it gets the idea
1808     dirac_priv_t *dpriv = priv->dpriv;
1809     int64_t start_pos = priv->input_position;
1810 
1811     seek_byte(cdata, priv->vstream->data_start);
1812 
1813     while (1) {
1814       int64_t input_pos;
1815       boolean done = FALSE;
1816 
1817       opriv->page_valid = 0;
1818 
1819       if (!(input_pos = get_page(cdata, priv->input_position))) {
1820         // should never reach here
1821         fprintf(stderr, "EOF1 while decoding\n");
1822         return FALSE;
1823       }
1824 
1825       priv->input_position += input_pos;
1826 
1827       if (ogg_page_serialno(&(opriv->current_page)) != priv->vstream->stream_id) continue;
1828       ogg_stream_pagein(&priv->vstream->stpriv->os, &(opriv->current_page));
1829 
1830       while (ogg_stream_packetout(&priv->vstream->stpriv->os, &opriv->op) > 0) {
1831         // feed packets to decoder
1832         SchroBuffer *schrobuffer;
1833         int state;
1834 
1835         schrobuffer = schro_buffer_new_with_data(opriv->op.packet, opriv->op.bytes);
1836         schro_decoder_autoparse_push(dpriv->schrodec, schrobuffer);
1837 
1838         state = schro_decoder_autoparse_wait(dpriv->schrodec);
1839 
1840         if (state == SCHRO_DECODER_FIRST_ACCESS_UNIT) {
1841           // should have our cdata now
1842           get_dirac_cdata(cdata, dpriv->schrodec);
1843           done = TRUE;
1844           break;
1845         }
1846         if (done) break;
1847       }
1848       if (done) break;
1849     }
1850 
1851     cdata->current_palette = cdata->palettes[0];
1852 
1853     // reset and seek back to start
1854     //fprintf(stderr,"got dirac fps=%.4f %d x %d\n",cdata->fps,cdata->width,cdata->height);
1855 
1856     schro_decoder_reset(dpriv->schrodec);
1857     seek_byte(cdata, start_pos);
1858     ogg_stream_reset(&priv->vstream->stpriv->os);
1859 
1860     // find first keyframe
1861     find_first_sync_frame(cdata, priv->vstream->data_start, opriv->total_bytes, &priv->kframe_offset);
1862 
1863     sprintf(cdata->video_name, "%s", "dirac");
1864   }
1865 
1866 #endif
1867 
1868   sprintf(cdata->container_name, "%s", "ogg");
1869 
1870   // audio part
1871   cdata->asigned = FALSE;
1872   cdata->achans = 0;
1873   cdata->ainterleaf = TRUE;
1874   cdata->asamps = 0;
1875 
1876   if (priv->astream) {
1877     sprintf(cdata->audio_name, "%s", "vorbis");
1878   } else memset(cdata->audio_name, 0, 1);
1879 
1880   if (isclone) return TRUE;
1881 
1882   // get duration
1883 
1884   if (priv->astream) {
1885     ogg_stream_reset(&priv->astream->stpriv->os);
1886     gpos = get_last_granulepos(cdata, priv->astream->stream_id);
1887     stream_duration =
1888       granulepos_2_time(priv->astream, gpos);
1889     priv->astream->duration = stream_duration;
1890     priv->astream->stpriv->last_granulepos = gpos;
1891     //printf("priv->astream duration is %.4f\n",stream_duration);
1892   }
1893 
1894   if (priv->vstream != NULL) {
1895     ogg_stream_reset(&priv->vstream->stpriv->os);
1896     gpos = get_last_granulepos(cdata, priv->vstream->stream_id);
1897 
1898     /*  kframe=gpos >> priv->vstream->priv->keyframe_granule_shift;
1899       priv->vstream->nframes = kframe + gpos-(kframe<<priv->vstream->priv->keyframe_granule_shift);*/
1900 
1901     priv->vstream->nframes = gpos;
1902 
1903     stream_duration =
1904       granulepos_2_time(priv->vstream, gpos);
1905     priv->vstream->duration = stream_duration;
1906     priv->vstream->stpriv->last_granulepos = gpos;
1907     //printf("priv->vstream duration is %.4f %ld\n",stream_duration,priv->vstream->nframes);
1908   }
1909 
1910   if (is_partial_clone) return TRUE;
1911 
1912   cdata->nframes = priv->vstream->nframes;
1913 
1914   if (cdata->width != cdata->frame_width || cdata->height != cdata->frame_height)
1915     fprintf(stderr, "ogg_decoder: info - frame size=%d x %d, pixel size=%d x %d\n", cdata->frame_width, cdata->frame_height,
1916             cdata->width,
1917             cdata->height);
1918 
1919   return TRUE;
1920 }
1921 
1922 
detach_stream(lives_clip_data_t * cdata)1923 static void detach_stream(lives_clip_data_t *cdata) {
1924   // close the file, free the decoder
1925   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
1926   ogg_t *opriv = priv->opriv;
1927 
1928 #ifdef HAVE_DIRAC
1929   dirac_priv_t *dpriv = priv->dpriv;
1930 #endif
1931 
1932   close(opriv->fd);
1933 
1934   ogg_sync_clear(&opriv->oy);
1935 
1936 #ifdef HAVE_THEORA
1937   if (priv->tpriv) {
1938     // theora only
1939     // TODO - call function in decoder
1940     theora_priv_t *tpriv = priv->tpriv;
1941     theora_clear(&tpriv->ts);
1942     theora_comment_clear(&tpriv->tc);
1943     theora_info_clear(&tpriv->ti);
1944     free(tpriv);
1945     priv->tpriv = NULL;
1946   }
1947 #endif
1948 
1949 #ifdef HAVE_DIRAC
1950   if (priv->dpriv) {
1951     schro_decoder_reset(dpriv->schrodec);
1952     if (dpriv->schroframe != NULL) {
1953       schro_frame_unref(dpriv->schroframe);
1954     }
1955     if (dpriv->schrodec != NULL) schro_decoder_free(dpriv->schrodec);
1956     dpriv->schrodec = NULL;
1957     dpriv->schroframe = NULL;
1958     free(dpriv);
1959     priv->dpriv = NULL;
1960   }
1961 #endif
1962 
1963   // free stream data
1964   if (priv->astream) {
1965     if (priv->astream->ext_data != NULL) free(priv->astream->ext_data);
1966     ogg_stream_clear(&priv->astream->stpriv->os);
1967     free(priv->astream->stpriv);
1968     free(priv->astream);
1969     priv->astream = NULL;
1970   }
1971 
1972   if (priv->vstream) {
1973     if (priv->vstream->ext_data != NULL) free(priv->vstream->ext_data);
1974     ogg_stream_clear(&priv->vstream->stpriv->os);
1975     free(priv->vstream->stpriv);
1976     free(priv->vstream);
1977     priv->vstream = NULL;
1978   }
1979 
1980   if (cdata->palettes) free(cdata->palettes);
1981   cdata->palettes = NULL;
1982 }
1983 
1984 
frame_to_gpos(lives_clip_data_t * cdata,int64_t kframe,int64_t frame)1985 static inline int64_t frame_to_gpos(lives_clip_data_t *cdata, int64_t kframe, int64_t frame) {
1986   // this is only valid for theora; for dirac there is no unique gpos for a particular frame
1987   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
1988   if (priv->vstream->stpriv->fourcc_priv == FOURCC_DIRAC) {
1989     return kframe;
1990   }
1991   return (kframe << priv->vstream->stpriv->keyframe_granule_shift) + (frame - kframe);
1992 }
1993 
1994 
ogg_seek(lives_clip_data_t * cdata,int64_t tframe,int64_t ppos_lower,int64_t ppos_upper,boolean can_exact)1995 static int64_t ogg_seek(lives_clip_data_t *cdata, int64_t tframe, int64_t ppos_lower, int64_t ppos_upper, boolean can_exact) {
1996   // for theora:
1997 
1998   // we do two passes here, first with can_exact set, then with can_exact unset
1999 
2000   // if can_exact is set, we find the granulepos nearest to or including the target granulepos
2001   // from this we extract an estimate of the keyframe (but note that there could be other keyframes between the found granulepos and the target)
2002 
2003   // on the second pass we find the highest granulepos < target. This places us just before or at the start of the target keyframe
2004 
2005   // when we come to decode, we start from this second position, discarding any completed packets on that page,
2006   // and read pages discarding packets until we get to the target frame
2007 
2008   // we return the granulepos which we find
2009 
2010   // for dirac:
2011 
2012   // we find the highest sync frame <= target frame, and return the sync_frame number
2013   // can_exact should be set to TRUE
2014 
2015   // the method used is bi-sections
2016   // first we divided the region into two, then we check the first keyframe of the upper part
2017   // if this is == target we return
2018   // if > target, or we find no keyframes, we go to the lower segment
2019   // this is then repeated until the segment size is too small to hold a packet, at which point we return our best
2020   // match
2021 
2022   int64_t start_pos, end_pos, pagepos = -1;
2023   int64_t frame, kframe, segsize;
2024 
2025   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
2026   ogg_t *opriv = priv->opriv;
2027 
2028   int64_t best_kframe = -1;
2029   int64_t best_frame = -1;
2030   int64_t best_pagepos = -1;
2031 
2032   //fprintf(stderr,"seek to frame %ld %d\n",tframe,can_exact);
2033 
2034   if (tframe < priv->kframe_offset) {
2035     priv->cpagepos = priv->vstream->data_start;
2036     if (!can_exact) {
2037       seek_byte(cdata, priv->vstream->data_start);
2038       return frame_to_gpos(cdata, priv->kframe_offset, 1);
2039     }
2040     return frame_to_gpos(cdata, priv->kframe_offset, 0);
2041   }
2042 
2043   if (ppos_lower < 0) ppos_lower = priv->vstream->data_start;
2044   if (ppos_upper < 0) ppos_upper = opriv->total_bytes;
2045   if (ppos_upper > opriv->total_bytes) ppos_upper = opriv->total_bytes;
2046 
2047   start_pos = ppos_lower;
2048   end_pos = ppos_upper;
2049 
2050   segsize = (end_pos - start_pos + 1) >> 1;
2051 
2052   do {
2053     // see if the frame lies in current segment
2054 
2055     if (start_pos < ppos_lower) start_pos = ppos_lower;
2056     if (end_pos > ppos_upper) end_pos = ppos_upper;
2057 
2058     if (start_pos >= end_pos) {
2059       if (start_pos == ppos_lower) {
2060         if (!can_exact) seek_byte(cdata, start_pos);
2061         priv->cpagepos = start_pos;
2062         return frame_to_gpos(cdata, priv->kframe_offset, 1);
2063       }
2064       break;
2065     }
2066 
2067     //fprintf(stderr,"check seg %ld to %ld for %ld\n",start_pos,end_pos,tframe);
2068 
2069     if (priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) pagepos = find_first_page(cdata, start_pos, end_pos, &kframe, &frame);
2070 #ifdef HAVE_DIRAC
2071     else {
2072       pagepos = find_first_sync_frame(cdata, start_pos, end_pos, &kframe);
2073       frame = kframe;
2074     }
2075 #endif
2076     if (pagepos != -1 && kframe != -1) {
2077       // found a keyframe
2078 
2079       //fprintf(stderr,"first sync_frame is %ld %ld\n",kframe,frame);
2080 
2081       if (can_exact && frame >= tframe && kframe <= tframe) {
2082         // got it !
2083         //fprintf(stderr,"seek got keyframe %ld for %ld\n",kframe,tframe);
2084         priv->cpagepos = pagepos;
2085         return frame_to_gpos(cdata, kframe, frame);
2086       }
2087 
2088       if ((kframe < tframe || (can_exact && kframe == tframe)) && kframe > best_kframe) {
2089         best_kframe = kframe;
2090         best_frame = frame;
2091         best_pagepos = pagepos;
2092       }
2093 
2094       if (frame >= tframe) {
2095         //fprintf(stderr,"checking lower segment\n");
2096         // check previous segment
2097         start_pos -= segsize;
2098         end_pos -= segsize;
2099       } else start_pos = pagepos;
2100     }
2101 
2102     // no keyframe found, check lower segment
2103     else {
2104       //fprintf(stderr,"no keyframe, checking lower segment\n");
2105       end_pos -= segsize;
2106       start_pos -= segsize;
2107     }
2108 
2109     segsize = (end_pos - start_pos + 1) >> 1;
2110     start_pos += segsize;
2111   } while (segsize > 64);
2112 
2113   if (best_kframe > -1) {
2114     int64_t gpos = frame_to_gpos(cdata, best_kframe, tframe);
2115     //fprintf(stderr,"seek2 got keyframe %ld %ld\n",best_kframe,best_frame);
2116     if (!can_exact) seek_byte(cdata, best_pagepos);
2117     priv->cpagepos = best_pagepos;
2118     // TODO - add to vlc
2119     if (priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) {
2120       pthread_mutex_lock(&priv->idxc->mutex);
2121       theora_index_entry_add((lives_clip_data_t *)cdata, gpos, priv->cpagepos);
2122       pthread_mutex_unlock(&priv->idxc->mutex);
2123     }
2124     gpos = frame_to_gpos(cdata, best_kframe, best_frame);
2125     return gpos;
2126   }
2127 
2128   // should never reach here
2129   //fprintf(stderr,"not found\n");
2130   return -1;
2131 }
2132 
2133 
2134 //////////////////////////////////////////
2135 // std functions
2136 
version(void)2137 const char *version(void) {
2138   return plugin_version;
2139 }
2140 
2141 
module_check_init(void)2142 const char *module_check_init(void) {
2143   indices = NULL;
2144   nidxc = 0;
2145   pthread_mutex_init(&indices_mutex, NULL);
2146   return NULL;
2147 }
2148 
2149 
init_cdata(lives_clip_data_t * data)2150 lives_clip_data_t *init_cdata(lives_clip_data_t *data) {
2151   lives_clip_data_t *cdata;
2152 
2153   if (!data) {
2154     cdata = cdata_new(NULL);
2155     cdata_stamp(cdata, plname, vmaj, vmin);
2156     cdata->palettes = malloc(4 * sizeof(int));
2157     cdata->palettes[3] = WEED_PALETTE_END;
2158   } else cdata = data;
2159 
2160   cdata->priv = calloc(1, sizeof(lives_ogg_priv_t));
2161 
2162   cdata->interlace = LIVES_INTERLACE_NONE;
2163   cdata->frame_gamma = WEED_GAMMA_UNKNOWN;
2164 
2165   return cdata;
2166 }
2167 
2168 
ogg_clone(lives_clip_data_t * cdata)2169 static lives_clip_data_t *ogg_clone(lives_clip_data_t *cdata) {
2170   lives_clip_data_t *clone = clone_cdata(cdata);
2171   lives_ogg_priv_t *dpriv, *spriv;
2172 
2173   cdata_stamp(clone, plname, vmaj, vmin);
2174 
2175   // create "priv" elements
2176   spriv = cdata->priv;
2177 
2178   if (spriv) {
2179     clone->priv = dpriv = (lives_ogg_priv_t *)calloc(1, sizeof(lives_ogg_priv_t));
2180     dpriv->inited = TRUE;
2181   } else {
2182     clone = init_cdata(clone);
2183     dpriv = clone->priv;
2184   }
2185 
2186   if (!clone->palettes) {
2187     clone->palettes = malloc(2 * sizeof(int));
2188     clone->palettes[1] = WEED_PALETTE_END;
2189   }
2190 
2191   if (!attach_stream(clone, TRUE)) {
2192     clip_data_free(clone);
2193     return NULL;
2194   }
2195 
2196   // create "priv" elements
2197   dpriv = clone->priv;
2198   spriv = cdata->priv;
2199 
2200   if (!attach_stream(clone, TRUE)) {
2201     clip_data_free(clone);
2202     return NULL;
2203   }
2204 
2205   if (spriv) {
2206     ogg_t *sopriv = spriv->opriv;
2207     ogg_t *dopriv = dpriv->opriv;
2208     dpriv->inited = TRUE;
2209     dopriv->total_bytes = sopriv->total_bytes;
2210     ogg_stream_reset(&dpriv->astream->stpriv->os);
2211     dpriv->astream->duration = spriv->astream->duration;
2212     dpriv->astream->stpriv->last_granulepos = spriv->astream->stpriv->last_granulepos;
2213 
2214     ogg_stream_reset(&dpriv->vstream->stpriv->os);
2215     dpriv->vstream->nframes = spriv->vstream->nframes;
2216     dpriv->vstream->duration = spriv->vstream->duration;
2217     dpriv->vstream->stpriv->last_granulepos = spriv->vstream->stpriv->last_granulepos;
2218   } else {
2219     clone->nclips = 1;
2220 
2221     ///////////////////////////////////////////////////////////
2222 
2223     sprintf(clone->container_name, "%s", "mkv");
2224 
2225     // clone->height was set when we attached the stream
2226 
2227     if (clone->frame_width == 0 || clone->frame_width < clone->width) clone->frame_width = clone->width;
2228     else {
2229       clone->offs_x = (clone->frame_width - clone->width) / 2;
2230     }
2231 
2232     if (clone->frame_height == 0 || clone->frame_height < clone->height) clone->frame_height = clone->height;
2233     else {
2234       clone->offs_y = (clone->frame_height - clone->height) / 2;
2235     }
2236 
2237     clone->frame_width = clone->width + clone->offs_x * 2;
2238     clone->frame_height = clone->height + clone->offs_y * 2;
2239 
2240     ////////////////////////////////////////////////////////////////////
2241 
2242     clone->asigned = TRUE;
2243     clone->ainterleaf = TRUE;
2244   }
2245 
2246   dpriv->last_frame = -1;
2247 
2248   return clone;
2249 }
2250 
2251 
get_clip_data(const char * URI,lives_clip_data_t * cdata)2252 lives_clip_data_t *get_clip_data(const char *URI, lives_clip_data_t *cdata) {
2253   // the first time this is called, caller should pass NULL as the clone
2254   // subsequent calls to this should re-use the same cdata
2255 
2256   // if the host wants a different URI, a different current_clip, or a different current_palette,
2257   // this must be called again with the same
2258   // cdata as the second parameter
2259   lives_ogg_priv_t *priv;
2260 
2261   if (!URI && cdata) {
2262     // create a clone of cdata - we also need to be able to handle a "fake" clone with only
2263     // URI, nframes and fps set (URI == NULL)
2264     return ogg_clone(cdata);
2265   }
2266 
2267   if (cdata && cdata->current_clip > 0) {
2268     // currently we only support one clip per container
2269     clip_data_free(cdata);
2270     return NULL;
2271   }
2272 
2273   if (!cdata) {
2274     cdata = init_cdata(NULL);
2275   }
2276 
2277   priv = (lives_ogg_priv_t *)cdata->priv;
2278 
2279   if (!cdata->URI || strcmp(URI, cdata->URI)) {
2280     if (cdata->URI) {
2281       detach_stream(cdata);
2282       free(cdata->URI);
2283     }
2284     cdata->URI = strdup(URI);
2285     if (!attach_stream(cdata, FALSE)) {
2286       free(cdata->URI);
2287       cdata->URI = NULL;
2288       clip_data_free(cdata);
2289       return NULL;
2290     }
2291     cdata->current_clip = 0;
2292   }
2293 
2294   if (!priv->vstream) {
2295     clip_data_free(cdata);
2296     return NULL;
2297   }
2298 
2299   cdata->nclips = 1;
2300 
2301   ///////////////////////////////////////////////////////////
2302 
2303   sprintf(cdata->container_name, "%s", "ogg");
2304 
2305   // cdata->height was set when we attached the stream
2306 
2307   if (cdata->frame_width == 0 || cdata->frame_width < cdata->width) cdata->frame_width = cdata->width;
2308   else {
2309     cdata->offs_x = (cdata->frame_width - cdata->width) / 2;
2310   }
2311 
2312   if (cdata->frame_height == 0 || cdata->frame_height < cdata->height) cdata->frame_height = cdata->height;
2313   else {
2314     cdata->offs_y = (cdata->frame_height - cdata->height) / 2;
2315   }
2316 
2317   cdata->frame_width = cdata->width + cdata->offs_x * 2;
2318   cdata->frame_height = cdata->height + cdata->offs_y * 2;
2319 
2320   ////////////////////////////////////////////////////////////////////
2321 
2322   cdata->asigned = TRUE;
2323   cdata->ainterleaf = TRUE;
2324 
2325   return cdata;
2326 }
2327 
2328 
2329 #ifdef HAVE_THEORA
2330 
ogg_theora_read(lives_clip_data_t * cdata,ogg_packet * op,yuv_buffer * yuv)2331 static boolean ogg_theora_read(lives_clip_data_t *cdata, ogg_packet *op, yuv_buffer *yuv) {
2332   // this packet is for our theora decoder
2333   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
2334   theora_priv_t *tpriv = priv->tpriv;
2335 
2336   //printf("skip is %d\n",priv->skip);
2337 
2338   if (theora_decode_packetin(&tpriv->ts, op) == 0) {
2339     if (priv->skip <= 0) {
2340       if (theora_decode_YUVout(&tpriv->ts, yuv) == 0) {
2341         priv->frame_out = TRUE;
2342       }
2343     }
2344   }
2345   return priv->frame_out;
2346 }
2347 
2348 
write_black_pixel(unsigned char * idst,int pal,int npixels,int y_black)2349 static size_t write_black_pixel(unsigned char *idst, int pal, int npixels, int y_black) {
2350   unsigned char *dst = idst;
2351   register int i;
2352 
2353   for (i = 0; i < npixels; i++) {
2354     switch (pal) {
2355     case WEED_PALETTE_RGBA32:
2356     case WEED_PALETTE_BGRA32:
2357       dst[0] = dst[1] = dst[2] = 0;
2358       dst[3] = 255;
2359       dst += 4;
2360       break;
2361     case WEED_PALETTE_ARGB32:
2362       dst[1] = dst[2] = dst[3] = 0;
2363       dst[0] = 255;
2364       dst += 4;
2365       break;
2366     case WEED_PALETTE_UYVY8888:
2367       dst[1] = dst[3] = y_black;
2368       dst[0] = dst[2] = 128;
2369       dst += 4;
2370       break;
2371     case WEED_PALETTE_YUYV8888:
2372       dst[0] = dst[2] = y_black;
2373       dst[1] = dst[3] = 128;
2374       dst += 4;
2375       break;
2376     case WEED_PALETTE_YUV888:
2377       dst[0] = y_black;
2378       dst[1] = dst[2] = 128;
2379       dst += 3;
2380       break;
2381     case WEED_PALETTE_YUVA8888:
2382       dst[0] = y_black;
2383       dst[1] = dst[2] = 128;
2384       dst[3] = 255;
2385       dst += 4;
2386       break;
2387     case WEED_PALETTE_YUV411:
2388       dst[0] = dst[3] = 128;
2389       dst[1] = dst[2] = dst[4] = dst[5] = y_black;
2390       dst += 6;
2391     default:
2392       break;
2393     }
2394   }
2395   return idst - dst;
2396 }
2397 #endif
2398 
2399 
2400 #ifdef HAVE_DIRAC
2401 
schroframe_to_pixel_data(SchroFrame * sframe,uint8_t ** pixel_data)2402 static void schroframe_to_pixel_data(SchroFrame *sframe, uint8_t **pixel_data) {
2403   uint8_t *s_y = sframe->components[0].data;
2404   uint8_t *s_u = sframe->components[1].data;
2405   uint8_t *s_v = sframe->components[2].data;
2406 
2407   uint8_t *d_y = pixel_data[0];
2408   uint8_t *d_u = pixel_data[1];
2409   uint8_t *d_v = pixel_data[2];
2410 
2411   register int i;
2412 
2413   boolean crow = FALSE;
2414 
2415   int mheight = (sframe->components[0].height >> 1) << 1;
2416 
2417   for (i = 0; i < mheight; i++) {
2418     memcpy(d_y, s_y, sframe->components[0].width);
2419     d_y += sframe->components[0].width;
2420     s_y += sframe->components[0].stride;
2421     if (sframe->components[1].height == sframe->components[0].height || crow) {
2422       memcpy(d_u, s_u, sframe->components[1].width);
2423       memcpy(d_v, s_v, sframe->components[2].width);
2424       d_u += sframe->components[1].width;
2425       d_v += sframe->components[2].width;
2426       s_u += sframe->components[1].stride;
2427       s_v += sframe->components[2].stride;
2428     }
2429     crow = !crow;
2430     sched_yield();
2431   }
2432 }
2433 
2434 
ogg_dirac_read(lives_clip_data_t * cdata,ogg_packet * op,uint8_t ** pixel_data,boolean cont)2435 static int64_t ogg_dirac_read(lives_clip_data_t *cdata, ogg_packet *op, uint8_t **pixel_data, boolean cont) {
2436   // this packet is for our dirac decoder
2437   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
2438   dirac_priv_t *dpriv = priv->dpriv;
2439   SchroDecoder *sd = dpriv->schrodec;
2440   SchroBuffer *schrobuffer;
2441   SchroFrame *schroframe;
2442   int state;
2443   int frame_width;
2444   int frame_height;
2445 
2446   int i;
2447 
2448   void *buf;
2449 
2450   if (!cont) {
2451     buf = malloc(op->bytes);
2452     memcpy(buf, op->packet, op->bytes);
2453 
2454     schrobuffer = schro_buffer_new_with_data(buf, op->bytes);
2455     schrobuffer->priv = buf;
2456 
2457     schrobuffer->free = SchroBufferFree;
2458 
2459     if (!schro_decoder_push_ready(sd)) fprintf(stderr, "decoder not ready !\n");
2460 
2461     schro_decoder_autoparse_push(sd, schrobuffer);
2462   }
2463 
2464   while (1) {
2465     state = schro_decoder_autoparse_wait(sd);
2466     switch (state) {
2467 
2468     case SCHRO_DECODER_EOS:
2469       printf("EOS\n");
2470       continue;
2471 
2472     case SCHRO_DECODER_FIRST_ACCESS_UNIT:
2473       // TODO - re-parse the video format
2474       //printf("fau\n");
2475       continue;
2476 
2477     case SCHRO_DECODER_NEED_BITS:
2478       //printf("need bits\n");
2479       return priv->frame_out;
2480 
2481     case SCHRO_DECODER_NEED_FRAME:
2482       //printf("need frame\n");
2483       schroframe = schro_frame_new();
2484       schro_frame_set_free_callback(schroframe, SchroFrameFree, NULL);
2485 
2486       if (cdata->current_palette == WEED_PALETTE_YUV420P) schroframe->format = SCHRO_FRAME_FORMAT_U8_420;
2487       if (cdata->current_palette == WEED_PALETTE_YUV422P) schroframe->format = SCHRO_FRAME_FORMAT_U8_422;
2488       if (cdata->current_palette == WEED_PALETTE_YUV444P) schroframe->format = SCHRO_FRAME_FORMAT_U8_444;
2489 
2490       schroframe->width = frame_width = cdata->frame_width;
2491       schroframe->height = frame_height = cdata->frame_height;
2492 
2493       for (i = 0; i < 3; i++) {
2494         schroframe->components[i].width = frame_width;
2495         schroframe->components[i].stride = frame_width;
2496         schroframe->components[i].height = frame_height;
2497         schroframe->components[i].length = frame_width * frame_height;
2498         schroframe->components[i].data = malloc(frame_width * frame_height);
2499 
2500         if (i == 0) {
2501           if (cdata->current_palette == WEED_PALETTE_YUV420P) {
2502             frame_width >>= 1;
2503             frame_height >>= 1;
2504           }
2505           if (cdata->current_palette == WEED_PALETTE_YUV422P) {
2506             frame_width >>= 1;
2507           }
2508 
2509         } else {
2510           schroframe->components[i].v_shift =
2511             SCHRO_FRAME_FORMAT_V_SHIFT(schroframe->format);
2512           schroframe->components[i].h_shift =
2513             SCHRO_FRAME_FORMAT_H_SHIFT(schroframe->format);
2514         }
2515       }
2516 
2517       schro_decoder_add_output_picture(sd, schroframe);
2518       break;
2519 
2520     case SCHRO_DECODER_OK:
2521       priv->last_frame = schro_decoder_get_picture_number(sd);
2522       //else priv->last_frame++;
2523       //fprintf(stderr,"dirac decoding picture %ld skip is %d, target %ld\n",priv->last_frame,priv->skip,priv->cframe);
2524       if ((schroframe = schro_decoder_pull(sd)) != NULL) {
2525         if (priv->cframe < 0 || priv->cframe == priv->last_frame) {
2526           priv->frame_out = TRUE;
2527           // copy data to pixel_data
2528           if (pixel_data != NULL) {
2529             schroframe_to_pixel_data(schroframe, pixel_data);
2530             dpriv->schroframe = schroframe;
2531             return TRUE;
2532           }
2533         }
2534         schro_frame_unref(schroframe);
2535         //priv->cframe++;
2536         //priv->skip--;
2537       }
2538       //else printf("Null frame !\n");
2539       if (pixel_data == NULL) return TRUE;
2540       break;
2541 
2542     case SCHRO_DECODER_ERROR:
2543       fprintf(stderr, "Schro decoder error !\n");
2544       priv->frame_out = TRUE;
2545       return priv->frame_out;
2546     }
2547   }
2548 
2549   return priv->frame_out;
2550 }
2551 
2552 #endif
2553 
2554 
ogg_data_process(lives_clip_data_t * cdata,void * yuvbuffer,boolean cont)2555 static boolean ogg_data_process(lives_clip_data_t *cdata, void *yuvbuffer, boolean cont) {
2556   // yuvbuffer must be cast to whatever decoder expects
2557 
2558   int64_t input_pos = 0;
2559   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
2560   ogg_t *opriv = priv->opriv;
2561 
2562   priv->frame_out = FALSE;
2563 
2564   if (!cont) ogg_stream_reset(&priv->vstream->stpriv->os);
2565 
2566 #ifdef HAVE_DIRAC
2567   if (priv->vstream->stpriv->fourcc_priv == FOURCC_DIRAC) {
2568     priv->ignore_packets = FALSE;
2569     if (!cont) {
2570       dirac_priv_t *dpriv = priv->dpriv;
2571       schro_decoder_reset(dpriv->schrodec);
2572       priv->last_frame = -1;
2573     }
2574   }
2575 #endif
2576 
2577   while (!priv->frame_out) {
2578     opriv->page_valid = 0;
2579 
2580     if (!cont) {
2581       if (!(input_pos = get_page(cdata, priv->input_position))) {
2582         // should never reach here (except when discovering last frame for dirac)
2583         //fprintf(stderr, "EOF1 while decoding\n");
2584         return FALSE;
2585       }
2586       priv->input_position += input_pos;
2587 
2588       if (ogg_page_serialno(&(opriv->current_page)) != priv->vstream->stream_id) continue;
2589       ogg_stream_pagein(&priv->vstream->stpriv->os, &(opriv->current_page));
2590       //printf("pulled page\n");
2591     }
2592 
2593     while ((cont && priv->vstream->stpriv->fourcc_priv == FOURCC_DIRAC) ||
2594            ogg_stream_packetout(&priv->vstream->stpriv->os, &opriv->op) > 0) {
2595 
2596       // cframe is the frame we are about to decode
2597 
2598       //fprintf(stderr,"cframe is %ld\n",priv->cframe);
2599 
2600 #ifdef HAVE_THEORA
2601       if (priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) {
2602 
2603         if (!priv->ignore_packets) {
2604           yuv_buffer *yuv = yuvbuffer;
2605           ogg_theora_read(cdata, &opriv->op, yuv);
2606         }
2607 
2608         priv->cframe++;
2609         priv->skip--;
2610       }
2611 #endif
2612 
2613 #ifdef HAVE_DIRAC
2614       if (priv->vstream->stpriv->fourcc_priv == FOURCC_DIRAC) {
2615         uint8_t **yuv = yuvbuffer;
2616 
2617         // TODO - if packet is seq start, add to index
2618         //printf("dec packet\n");
2619 
2620         ogg_dirac_read(cdata, &opriv->op, yuv, cont);
2621 
2622         // dirac can pull several frames from the same packet
2623         if (!priv->frame_out) cont = FALSE;
2624       }
2625 #endif
2626 
2627       if (priv->frame_out) break;
2628 
2629       sched_yield();
2630     }
2631     priv->ignore_packets = FALSE; // start decoding packets
2632 
2633     cont = FALSE;
2634   }
2635 
2636   return TRUE;
2637 }
2638 
2639 
get_frame(const lives_clip_data_t * cdata,int64_t tframe,int * rowstrides,int height,void ** pixel_data)2640 boolean get_frame(const lives_clip_data_t *cdata, int64_t tframe, int *rowstrides, int height, void **pixel_data) {
2641   // seek to frame, and return pixel_data
2642 
2643   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
2644 
2645 #ifdef HAVE_THEORA
2646   yuv_buffer yuv;
2647   register int i;
2648 #endif
2649 
2650 #ifdef HAVE_DIRAC
2651   dirac_priv_t *dpriv = priv->dpriv;
2652   ogg_t *opriv = priv->opriv;
2653 #endif
2654 
2655   int64_t kframe = -1, xkframe;
2656   boolean cont = FALSE;
2657   int max_frame_diff;
2658   int64_t granulepos = 0;
2659   int64_t ppos_lower = -1, ppos_upper = -1;
2660 
2661   static index_entry *fidx = NULL;
2662 
2663 #ifdef HAVE_THEORA
2664 
2665   register int p;
2666 
2667   unsigned char *dst, *src;
2668 
2669   int y_black = (cdata->YUV_clamping == WEED_YUV_CLAMPING_CLAMPED) ? 16 : 0;
2670   unsigned char black[4] = {0, 0, 0, 255};
2671 
2672   int xheight = (cdata->frame_height >> 1) << 1, pal = cdata->current_palette, nplanes = 1, dstwidth = cdata->width, psize = 1;
2673   int btop = cdata->offs_y, bbot = xheight - 1 - btop;
2674   int bleft = cdata->offs_x, bright = cdata->frame_width - cdata->width - bleft;
2675 
2676   if (pixel_data) {
2677     if (pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P || pal == WEED_PALETTE_YUV422P || pal == WEED_PALETTE_YUV444P) {
2678       nplanes = 3;
2679       black[0] = y_black;
2680       black[1] = black[2] = 128;
2681     } else if (pal == WEED_PALETTE_YUVA4444P) {
2682       nplanes = 4;
2683       black[0] = y_black;
2684       black[1] = black[2] = 128;
2685       black[3] = 255;
2686     }
2687 
2688     if (pal == WEED_PALETTE_RGB24 || pal == WEED_PALETTE_BGR24) psize = 3;
2689 
2690     if (pal == WEED_PALETTE_RGBA32 || pal == WEED_PALETTE_BGRA32 || pal == WEED_PALETTE_ARGB32 || pal == WEED_PALETTE_UYVY8888 ||
2691         pal == WEED_PALETTE_YUYV8888 || pal == WEED_PALETTE_YUV888 || pal == WEED_PALETTE_YUVA8888) psize = 4;
2692 
2693     if (pal == WEED_PALETTE_YUV411) psize = 6;
2694 
2695     if (pal == WEED_PALETTE_A1) dstwidth >>= 3;
2696 
2697     dstwidth *= psize;
2698 
2699     if (cdata->frame_height > cdata->height && height == cdata->height) {
2700       // host ignores vertical border
2701       btop = 0;
2702       xheight = (cdata->height >> 1) << 1;
2703       bbot = xheight - 1;
2704     }
2705 
2706     if (cdata->frame_width > cdata->width && rowstrides[0] < cdata->frame_width * psize) {
2707       // host ignores horizontal border
2708       bleft = bright = 0;
2709     }
2710   }
2711 
2712 #endif
2713 
2714   priv->current_pos = priv->input_position;
2715 
2716   max_frame_diff = 2 << (priv->vstream->stpriv->keyframe_granule_shift - 2);
2717 
2718   tframe += priv->kframe_offset;
2719 
2720   if (tframe == priv->last_frame) {
2721 #ifdef HAVE_THEORA
2722     if (priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) {
2723       theora_priv_t *tpriv = priv->tpriv;
2724       theora_decode_YUVout(&tpriv->ts, &yuv);
2725     }
2726 #endif
2727 #ifdef HAVE_DIRAC
2728     if (priv->vstream->stpriv->fourcc_priv == FOURCC_DIRAC) {
2729       dirac_priv_t *dpriv = priv->dpriv;
2730       if (dpriv->schroframe) {
2731         schroframe_to_pixel_data(dpriv->schroframe, (uint8_t **)pixel_data);
2732         return TRUE;
2733       }
2734       return FALSE;
2735     }
2736 #endif
2737   } else {
2738 #ifdef HAVE_DIRAC
2739     if (priv->vstream->stpriv->fourcc_priv == FOURCC_DIRAC && dpriv->schroframe != NULL) {
2740       schro_frame_unref(dpriv->schroframe);
2741       dpriv->schroframe = NULL;
2742 
2743       ppos_lower = priv->vstream->data_start;
2744       ppos_upper = opriv->total_bytes;
2745 
2746       max_frame_diff = 16;
2747     }
2748 #endif
2749 
2750     if (tframe <= priv->last_frame || tframe - priv->last_frame > max_frame_diff) {
2751 
2752       // this is a big kludge, because really for dirac we should always seek from the first frame
2753       // because frames can refer to any earlier frame
2754       if (priv->vstream->stpriv->fourcc_priv == FOURCC_DIRAC) {
2755         tframe -= DIRAC_EXTRA_FRAMES ;
2756       }
2757 
2758       // need to find a new kframe
2759       pthread_mutex_lock(&priv->idxc->mutex);
2760       fidx = get_bounds_for((lives_clip_data_t *)cdata, tframe, &ppos_lower, &ppos_upper);
2761       if (!fidx) {
2762         //printf("pt a\n");
2763         int64_t last_ret_frame = priv->last_frame;
2764         pthread_mutex_unlock(&priv->idxc->mutex);
2765         granulepos = ogg_seek((lives_clip_data_t *)cdata, tframe, ppos_lower, ppos_upper, TRUE);
2766         pthread_mutex_lock(&priv->idxc->mutex);
2767         priv->last_frame = last_ret_frame;
2768         if (granulepos == -1) return FALSE; // should never happen...
2769       } else granulepos = fidx->value;
2770       pthread_mutex_unlock(&priv->idxc->mutex);
2771       //printf("pt a2\n");
2772 
2773       if (priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) {
2774         kframe = granulepos >> priv->vstream->stpriv->keyframe_granule_shift;
2775         //printf("kframe %ld tframe %ld\n",kframe,tframe);
2776       } else {
2777         kframe = granulepos;
2778         // part 2 of the dirac kludge
2779         tframe += DIRAC_EXTRA_FRAMES;
2780       }
2781 
2782       if (kframe < priv->kframe_offset) kframe = priv->kframe_offset;
2783     } else kframe = priv->last_kframe;
2784 
2785     priv->ignore_packets = FALSE;
2786 
2787     //printf("cf %ld and %ld\n",tframe,priv->last_frame);
2788 
2789     if (tframe > priv->last_frame && (tframe - priv->last_frame <= max_frame_diff ||
2790                                       (kframe == priv->last_kframe && priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA))) {
2791       // same keyframe as last time, or next frame; we can continue where we left off
2792       cont = TRUE;
2793       priv->skip = tframe - priv->last_frame - 1;
2794       priv->input_position = priv->current_pos;
2795       //printf("CONTINUING %ld %ld %ld %ld\n",tframe,priv->last_frame,kframe,priv->last_kframe);
2796     } else {
2797       if (!fidx || priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) {
2798         if (priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) {
2799           pthread_mutex_lock(&priv->idxc->mutex);
2800           get_bounds_for((lives_clip_data_t *)cdata, kframe - 1, &ppos_lower, &ppos_upper);
2801           pthread_mutex_unlock(&priv->idxc->mutex);
2802           granulepos = ogg_seek((lives_clip_data_t *)cdata, kframe - 1, ppos_lower, ppos_upper, FALSE);
2803           //fprintf(stderr,"starting from found gpos %ld\n",granulepos);
2804 
2805           xkframe = granulepos >> priv->vstream->stpriv->keyframe_granule_shift;
2806 
2807           pthread_mutex_lock(&priv->idxc->mutex);
2808           get_bounds_for((lives_clip_data_t *)cdata, xkframe - 1, &ppos_lower, &ppos_upper);
2809           pthread_mutex_unlock(&priv->idxc->mutex);
2810           granulepos = ogg_seek((lives_clip_data_t *)cdata, xkframe - 1, ppos_lower, ppos_upper, FALSE);
2811           //fprintf(stderr,"starting from found gpos %ld\n",granulepos);
2812 
2813           xkframe = granulepos >> priv->vstream->stpriv->keyframe_granule_shift;
2814 
2815           priv->cframe = xkframe + granulepos - (xkframe <<
2816                                                  priv->vstream->stpriv->keyframe_granule_shift); // cframe will be the next frame we decode
2817           //printf("xkframe is %ld %ld\n",xkframe,priv->cframe);
2818         } else {
2819           priv->cframe = kframe;
2820           priv->input_position = priv->cpagepos;
2821           //printf("SEEK TO %ld\n",priv->cpagepos);
2822         }
2823 
2824         if (priv->input_position == priv->vstream->data_start) {
2825           priv->cframe = kframe = priv->kframe_offset;
2826         }
2827 
2828         priv->skip = tframe - priv->cframe;
2829         //printf("skip is %ld - %ld = %ld\n",tframe,priv->cframe,priv->skip);
2830       } else {
2831         // same keyframe as last time
2832         priv->input_position = fidx->pagepos;
2833         priv->cframe = kframe = fidx->value;
2834         priv->skip = tframe - priv->cframe + 1;
2835       }
2836 
2837       if (priv->input_position > priv->vstream->data_start) {
2838         priv->ignore_packets = TRUE;
2839       }
2840     }
2841 
2842     //fprintf(stderr,"getting yuv at %ld\n",input_position);
2843 
2844     priv->last_frame = tframe;
2845     priv->last_kframe = kframe;
2846 
2847 #ifdef HAVE_THEORA
2848     if (priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) {
2849       if (!ogg_data_process((lives_clip_data_t *)cdata, &yuv, cont)) return FALSE;
2850     }
2851 #endif
2852 
2853 #ifdef HAVE_DIRAC
2854     if (priv->vstream->stpriv->fourcc_priv == FOURCC_DIRAC) {
2855       schro_decoder_set_earliest_frame(dpriv->schrodec, tframe);
2856       priv->cframe = tframe;
2857       return ogg_data_process((lives_clip_data_t *)cdata, pixel_data, cont);
2858     }
2859 #endif
2860   }
2861 
2862 #ifdef HAVE_THEORA
2863   if (priv->vstream->stpriv->fourcc_priv == FOURCC_THEORA) {
2864     size_t srcadd;
2865 
2866     for (p = 0; p < nplanes; p++) {
2867       dst = pixel_data[p];
2868 
2869       switch (p) {
2870       case 0:
2871         src = yuv.y;
2872         srcadd = yuv.y_stride;
2873         break;
2874       case 1:
2875         src = yuv.u;
2876         srcadd = yuv.uv_stride;
2877         break;
2878       case 2:
2879         src = yuv.v;
2880         srcadd = yuv.uv_stride;
2881         break;
2882       default:
2883         srcadd = 0;
2884         src = NULL;
2885         break;
2886       }
2887 
2888       for (i = 0; i < xheight; i++) {
2889         if (i < btop || i > bbot) {
2890           // top or bottom border, copy black row
2891           if (pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P || pal == WEED_PALETTE_YUV422P ||
2892               pal == WEED_PALETTE_YUV444P || pal == WEED_PALETTE_YUVA4444P
2893               || pal == WEED_PALETTE_RGB24 || pal == WEED_PALETTE_BGR24) {
2894             memset(dst, black[p], dstwidth + (bleft + bright)*psize);
2895             dst += dstwidth + (bleft + bright) * psize;
2896           } else dst += write_black_pixel(dst, pal, dstwidth / psize + bleft + bright, y_black);
2897           continue;
2898         }
2899 
2900         if (bleft > 0) {
2901           if (pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P
2902               || pal == WEED_PALETTE_YUV422P || pal == WEED_PALETTE_YUV444P ||
2903               pal == WEED_PALETTE_YUVA4444P || pal == WEED_PALETTE_RGB24 || pal == WEED_PALETTE_BGR24) {
2904             memset(dst, black[p], bleft * psize);
2905             dst += bleft * psize;
2906           } else dst += write_black_pixel(dst, pal, bleft, y_black);
2907         }
2908 
2909         memcpy(dst, src, srcadd);
2910         dst += dstwidth;
2911 
2912         if (bright > 0) {
2913           if (pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P
2914               || pal == WEED_PALETTE_YUV422P || pal == WEED_PALETTE_YUV444P ||
2915               pal == WEED_PALETTE_YUVA4444P || pal == WEED_PALETTE_RGB24 || pal == WEED_PALETTE_BGR24) {
2916             memset(dst, black[p], bright * psize);
2917             dst += bright * psize;
2918           } else dst += write_black_pixel(dst, pal, bright, y_black);
2919         }
2920 
2921         src += srcadd;
2922       }
2923       if (p == 0 && (pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P || pal == WEED_PALETTE_YUV422P)) {
2924         dstwidth >>= 1;
2925         bleft >>= 1;
2926         bright >>= 1;
2927       }
2928       if (p == 0 && (pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P)) {
2929         xheight >>= 1;
2930         btop >>= 1;
2931         bbot >>= 1;
2932       }
2933     }
2934     return TRUE;
2935   }
2936 #endif
2937 
2938   return FALSE;
2939 }
2940 
2941 
clip_data_free(lives_clip_data_t * cdata)2942 void clip_data_free(lives_clip_data_t *cdata) {
2943   lives_ogg_priv_t *priv = (lives_ogg_priv_t *)cdata->priv;
2944 
2945   // free index entries
2946   if (priv->idxc) idxc_release(cdata);
2947 
2948   if (cdata->URI) {
2949     detach_stream(cdata);
2950   }
2951 
2952   if (priv->opriv) free(priv->opriv);
2953   lives_struct_free(&cdata->lsd);
2954 }
2955 
2956 
module_unload(void)2957 void module_unload(void) {
2958   idxc_release_all();
2959 }
2960 
2961