OSDN Git Service

gitattirubes test 2
[handbrake-jp/handbrake-jp.git] / libhb / render.c
1 /* $Id: render.c,v 1.17 2005/04/14 17:37:54 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.fr/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include "hb.h"
8 #include "hbffmpeg.h"
9
10 struct hb_work_private_s
11 {
12     hb_job_t * job;
13
14     struct SwsContext  * context;
15     AVPicture            pic_tmp_in;
16     AVPicture            pic_tmp_crop;
17     AVPicture            pic_tmp_out;
18     hb_buffer_t        * buf_scale;
19     hb_fifo_t          * subtitle_queue;
20     hb_fifo_t          * delay_queue;
21     int                  dropped_frames;
22     int                  extended_frames;
23     uint64_t             last_start[4];
24     uint64_t             last_stop[4];
25     uint64_t             lost_time[4];
26     uint64_t             total_lost_time;
27     uint64_t             total_gained_time;
28     int64_t              chapter_time;
29     int                  chapter_val;
30     int                  count_frames;      // frames output so far
31     double               frame_rate;        // 90KHz ticks per frame (for CFR/PFR)
32     double               out_last_stop;     // where last frame ended (for CFR/PFR)
33     int                  drops;             // frames dropped (for CFR/PFR)
34     int                  dups;              // frames duped (for CFR/PFR)
35 };
36
37 int  renderInit( hb_work_object_t *, hb_job_t * );
38 int  renderWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
39 void renderClose( hb_work_object_t * );
40
41 hb_work_object_t hb_render =
42 {
43     WORK_RENDER,
44     "Renderer",
45     renderInit,
46     renderWork,
47     renderClose
48 };
49
50 /*
51  * getU() & getV()
52  *
53  * Utility function that finds where the U is in the YUV sub-picture
54  *
55  * The Y data is at the top, followed by U and V, but the U and V
56  * are half the width of the Y, i.e. each chroma element covers 2x2
57  * of the Y's.
58  */
59 static uint8_t *getU(uint8_t *data, int width, int height, int x, int y)
60 {
61     return(&data[(y>>1) * ((width+1)>>1) + (x>>1) + width*height]);
62 }
63
64 static uint8_t *getV(uint8_t *data, int width, int height, int x, int y)
65 {
66     int w2 = (width+1) >> 1, h2 = (height+1) >> 1;
67     return(&data[(y>>1) * w2 + (x>>1) + width*height + w2*h2]);
68 }
69
70 static void ApplySub( hb_job_t * job, hb_buffer_t * buf,
71                       hb_buffer_t ** _sub )
72 {
73     hb_buffer_t * sub = *_sub;
74     hb_title_t * title = job->title;
75     int i, j, offset_top, offset_left, margin_top, margin_percent;
76     uint8_t * lum, * alpha, * out, * sub_chromaU, * sub_chromaV;
77
78     /*
79      * Percent of height of picture that form a margin that subtitles
80      * should not be displayed within.
81      */
82     margin_percent = 2;
83
84     if( !sub )
85     {
86         return;
87     }
88
89     /*
90      * If necessary, move the subtitle so it is not in a cropped zone.
91      * When it won't fit, we center it so we lose as much on both ends.
92      * Otherwise we try to leave a 20px or 2% margin around it.
93      */
94     margin_top = ( ( title->height - job->crop[0] - job->crop[1] ) *
95                    margin_percent ) / 100;
96
97     if( margin_top > 20 )
98     {
99         /*
100          * A maximum margin of 20px regardless of height of the picture.
101          */
102         margin_top = 20;
103     }
104
105     if( sub->height > title->height - job->crop[0] - job->crop[1] -
106         ( margin_top * 2 ) )
107     {
108         /*
109          * The subtitle won't fit in the cropped zone, so center
110          * it vertically so we fit in as much as we can.
111          */
112         offset_top = job->crop[0] + ( title->height - job->crop[0] -
113                                       job->crop[1] - sub->height ) / 2;
114     }
115     else if( sub->y < job->crop[0] + margin_top )
116     {
117         /*
118          * The subtitle fits in the cropped zone, but is currently positioned
119          * within our top margin, so move it outside of our margin.
120          */
121         offset_top = job->crop[0] + margin_top;
122     }
123     else if( sub->y > title->height - job->crop[1] - margin_top - sub->height )
124     {
125         /*
126          * The subtitle fits in the cropped zone, and is not within the top
127          * margin but is within the bottom margin, so move it to be above
128          * the margin.
129          */
130         offset_top = title->height - job->crop[1] - margin_top - sub->height;
131     }
132     else
133     {
134         /*
135          * The subtitle is fine where it is.
136          */
137         offset_top = sub->y;
138     }
139
140     if( sub->width > title->width - job->crop[2] - job->crop[3] - 40 )
141         offset_left = job->crop[2] + ( title->width - job->crop[2] -
142                 job->crop[3] - sub->width ) / 2;
143     else if( sub->x < job->crop[2] + 20 )
144         offset_left = job->crop[2] + 20;
145     else if( sub->x > title->width - job->crop[3] - 20 - sub->width )
146         offset_left = title->width - job->crop[3] - 20 - sub->width;
147     else
148         offset_left = sub->x;
149
150     lum   = sub->data;
151     alpha = lum + sub->width * sub->height;
152     sub_chromaU = alpha + sub->width * sub->height;
153     sub_chromaV = sub_chromaU + sub->width * sub->height;
154
155     out   = buf->data + offset_top * title->width + offset_left;
156
157     for( i = 0; i < sub->height; i++ )
158     {
159         if( offset_top + i >= 0 && offset_top + i < title->height )
160         {
161             for( j = 0; j < sub->width; j++ )
162             {
163                 if( offset_left + j >= 0 && offset_left + j < title->width )
164                 {
165                     uint8_t *chromaU, *chromaV;
166
167                     /*
168                      * Merge the luminance and alpha with the picture
169                      */
170                     out[j] = ( (uint16_t) out[j] * ( 16 - (uint16_t) alpha[j] ) +
171                                (uint16_t) lum[j] * (uint16_t) alpha[j] ) >> 4;
172                     /*
173                      * Set the chroma (colour) based on whether there is
174                      * any alpha at all. Don't try to blend with the picture.
175                      */
176                     chromaU = getU(buf->data, title->width, title->height,
177                                    offset_left+j, offset_top+i);
178
179                     chromaV = getV(buf->data, title->width, title->height,
180                                    offset_left+j, offset_top+i);
181
182                     if( alpha[j] > 0 )
183                     {
184                         /*
185                          * Add the chroma from the sub-picture, as this is
186                          * not a transparent element.
187                          */
188                         *chromaU = sub_chromaU[j];
189                         *chromaV = sub_chromaV[j];
190                     }
191                 }
192             }
193         }
194
195         lum   += sub->width;
196         alpha += sub->width;
197         sub_chromaU += sub->width;
198         sub_chromaV += sub->width;
199         out   += title->width;
200     }
201
202     hb_buffer_close( _sub );
203 }
204
205 // delete the buffer 'out' from the chain of buffers whose head is 'buf_out'.
206 // out & buf_out must be non-null (checks prior to anywhere this routine
207 // can be called guarantee this) and out must be on buf_out's chain
208 // (all places that call this get 'out' while traversing the chain).
209 // 'out' is freed and its predecessor is returned.
210 static hb_buffer_t *delete_buffer_from_chain( hb_buffer_t **buf_out, hb_buffer_t *out)
211 {
212     hb_buffer_t *succ = out->next;
213     hb_buffer_t *pred = *buf_out;
214     if ( pred == out )
215     {
216         // we're deleting the first buffer
217         *buf_out = succ;
218     }
219     else
220     {
221         // target isn't the first buf so search for its predecessor.
222         while ( pred->next != out )
223         {
224             pred = pred->next;
225         }
226         // found 'out' - remove it from the chain
227         pred->next = succ;
228     }
229     out->next = 0;
230     hb_buffer_close( &out );
231     return succ;
232 }
233
234 // insert buffer 'succ' after buffer chain element 'pred'.
235 // caller must guarantee that 'pred' and 'succ' are non-null.
236 static hb_buffer_t *insert_buffer_in_chain( hb_buffer_t *pred, hb_buffer_t *succ )
237 {
238     succ->next = pred->next;
239     pred->next = succ;
240     return succ;
241 }
242
243 // This section of the code implements video frame rate control.
244 // Since filters are allowed to duplicate and drop frames (which
245 // changes the timing), this has to be the last thing done in render.
246 //
247 // There are three options, selected by the value of job->cfr:
248 //   0 - Variable Frame Rate (VFR) or 'same as source': frame times
249 //       are left alone
250 //   1 - Constant Frame Rate (CFR): Frame timings are adjusted so that all
251 //       frames are exactly job->vrate_base ticks apart. Frames are dropped
252 //       or duplicated if necessary to maintain this spacing.
253 //   2 - Peak Frame Rate (PFR): job->vrate_base is treated as the peak
254 //       average frame rate. I.e., the average frame rate (current frame
255 //       end time divided by number of frames so far) is never allowed to be
256 //       greater than job->vrate_base and frames are dropped if necessary
257 //       to keep the average under this value. Other than those drops, frame
258 //       times are left alone.
259 //
260
261 static void adjust_frame_rate( hb_work_private_t *pv, hb_buffer_t **buf_out )
262 {
263     hb_buffer_t *out = *buf_out;
264
265     while ( out && out->size > 0 )
266     {
267         // this frame has to start where the last one stopped.
268         out->start = pv->out_last_stop;
269
270         // compute where this frame would stop if the frame rate were constant
271         // (this is our target stopping time for CFR and earliest possible
272         // stopping time for PFR).
273         double cfr_stop = pv->frame_rate * ( pv->count_frames + 1 );
274
275         if ( cfr_stop - (double)out->stop >= pv->frame_rate )
276         {
277             // This frame stops a frame time or more in the past - drop it
278             // but don't lose its chapter mark.
279             if ( out->new_chap )
280             {
281                 pv->chapter_time = out->start;
282                 pv->chapter_val = out->new_chap;
283             }
284             ++pv->drops;
285             out = delete_buffer_from_chain( buf_out, out );
286             continue;
287         }
288
289         // at this point we know that this frame doesn't push the average
290         // rate over the limit so we just pass it on for PFR. For CFR we're
291         // going to return it (with its start & stop times modified) and
292         // we may have to dup it.
293         ++pv->count_frames;
294         if ( pv->job->cfr > 1 )
295         {
296             // PFR - we're going to keep the frame but may need to
297             // adjust it's stop time to meet the average rate constraint.
298             if ( out->stop <= cfr_stop )
299             {
300                 out->stop = cfr_stop;
301             }
302         }
303         else
304         {
305             // we're doing CFR so we have to either trim some time from a
306             // buffer that ends too far in the future or, if the buffer is
307             // two or more frame times long, split it into multiple pieces,
308             // each of which is a frame time long.
309             double excess_dur = (double)out->stop - cfr_stop;
310             out->stop = cfr_stop;
311             for ( ; excess_dur >= pv->frame_rate; excess_dur -= cfr_stop )
312             {
313                 /* next frame too far ahead - dup current frame */
314                 hb_buffer_t *dup = hb_buffer_init( out->size );
315                 memcpy( dup->data, out->data, out->size );
316                 hb_buffer_copy_settings( dup, out );
317                 dup->new_chap = 0;
318                 dup->start = cfr_stop;
319                 cfr_stop += pv->frame_rate;
320                 dup->stop = cfr_stop;
321                 out = insert_buffer_in_chain( out, dup );
322                 ++pv->dups;
323                 ++pv->count_frames;
324             }
325         }
326         pv->out_last_stop = out->stop;
327         out = out->next;
328     }
329 }
330
331 int renderWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
332                 hb_buffer_t ** buf_out )
333 {
334     hb_work_private_t * pv = w->private_data;
335     hb_job_t   * job   = pv->job;
336     hb_title_t * title = job->title;
337     hb_buffer_t * in = *buf_in, * buf_tmp_in = *buf_in;
338     hb_buffer_t * ivtc_buffer = NULL;
339
340     if( in->size <= 0 )
341     {
342         hb_buffer_t *head = NULL, *tail = NULL, *next;
343         int counter = 2;
344
345         /* If the input buffer is end of stream, send out an empty one
346          * to the next stage as well. To avoid losing the contents of
347          * the delay queue connect the buffers in the delay queue in 
348          * the correct order, and add the end of stream buffer to the
349          * end.
350          */     
351         while( ( next = hb_fifo_get( pv->delay_queue ) ) != NULL )
352         {
353             
354             /* We can't use the given time stamps. Previous frames
355                might already have been extended, throwing off the
356                raw values fed to render.c. Instead, their
357                stop and start times are stored in arrays.
358                The 4th cached frame will be the to use.
359                If it needed its duration extended to make up
360                lost time, it will have happened above. */
361             next->start = pv->last_start[counter];
362             next->stop = pv->last_stop[counter--];
363             
364             if( !head && !tail )
365             {
366                 head = tail = next;
367             } else {
368                 tail->next = next;
369                 tail = next;
370             }
371         }
372         if( tail )
373         {
374             tail->next = in;
375             *buf_out = head;
376             if ( job->cfr )
377             {
378                 adjust_frame_rate( pv, buf_out );
379             }
380         } else {
381             *buf_out = in;
382         }     
383         *buf_in = NULL;
384         return HB_WORK_DONE;
385     }
386
387     /*
388      * During the indepth_scan ditch the buffers here before applying filters or attempting to
389      * use the subtitles.
390      */
391     if( job->indepth_scan )
392     {
393         *buf_out = NULL;
394         return HB_WORK_OK;
395     }
396
397     /* Push subtitles onto queue just in case we need to delay a frame */
398     if( in->sub )
399     {
400         hb_fifo_push( pv->subtitle_queue, in->sub );
401     }
402     else
403     {
404         hb_fifo_push( pv->subtitle_queue,  hb_buffer_init(0) );
405     }
406
407     /* If there's a chapter mark remember it in case we delay or drop its frame */
408     if( in->new_chap )
409     {
410         pv->chapter_time = in->start;
411         pv->chapter_val = in->new_chap;
412         in->new_chap = 0;
413     }
414
415     /* Setup render buffer */
416     hb_buffer_t * buf_render = hb_video_buffer_init( job->width, job->height );
417
418     /* Apply filters */
419     if( job->filters )
420     {
421         int filter_count = hb_list_count( job->filters );
422         int i;
423
424         for( i = 0; i < filter_count; i++ )
425         {
426             hb_filter_object_t * filter = hb_list_item( job->filters, i );
427
428             if( !filter )
429             {
430                 continue;
431             }
432
433             hb_buffer_t * buf_tmp_out = NULL;
434
435             int result = filter->work( buf_tmp_in,
436                                        &buf_tmp_out,
437                                        PIX_FMT_YUV420P,
438                                        title->width,
439                                        title->height,
440                                        filter->private_data );
441
442             /*
443              * FILTER_OK:      set temp buffer to filter buffer, continue
444              * FILTER_DELAY:   set temp buffer to NULL, abort
445              * FILTER_DROP:    set temp buffer to NULL, pop subtitle, abort
446              * FILTER_FAILED:  leave temp buffer alone, continue
447              */
448             if( result == FILTER_OK )
449             {
450                 buf_tmp_in = buf_tmp_out;
451             }
452             else if( result == FILTER_DELAY )
453             {
454                 buf_tmp_in = NULL;
455                 break;
456             }
457             else if( result == FILTER_DROP )
458             {
459                 /* We need to compensate for the time lost by dropping this frame.
460                    Spread its duration out in quarters, because usually dropped frames
461                    maintain a 1-out-of-5 pattern and this spreads it out amongst the remaining ones.
462                    Store these in the lost_time array, which has 4 slots in it.
463                    Because not every frame duration divides evenly by 4, and we can't lose the
464                    remainder, we have to go through an awkward process to preserve it in the 4th array index. */
465                 uint64_t temp_duration = buf_tmp_out->stop - buf_tmp_out->start;
466                 pv->lost_time[0] += (temp_duration / 4);
467                 pv->lost_time[1] += (temp_duration / 4);
468                 pv->lost_time[2] += (temp_duration / 4);
469                 pv->lost_time[3] += ( temp_duration - (temp_duration / 4) - (temp_duration / 4) - (temp_duration / 4) );
470
471                 pv->total_lost_time += temp_duration;
472                 pv->dropped_frames++;
473
474                 /* Pop the frame's subtitle and dispose of it. */
475                 hb_buffer_t * subtitles = hb_fifo_get( pv->subtitle_queue );
476                 hb_buffer_close( &subtitles );
477                 buf_tmp_in = NULL;
478                 break;
479             }
480         }
481     }
482
483     if( buf_tmp_in )
484     {
485         /* Cache frame start and stop times, so we can renumber
486            time stamps if dropping frames for VFR.              */
487         int i;
488         for( i = 3; i >= 1; i-- )
489         {
490             pv->last_start[i] = pv->last_start[i-1];
491             pv->last_stop[i] = pv->last_stop[i-1];
492         }
493
494         /* In order to make sure we have continuous time stamps, store
495            the current frame's duration as starting when the last one stopped. */
496         pv->last_start[0] = pv->last_stop[1];
497         pv->last_stop[0] = pv->last_start[0] + (buf_tmp_in->stop - buf_tmp_in->start);
498     }
499
500     /* Apply subtitles */
501     if( buf_tmp_in )
502     {
503         hb_buffer_t * subtitles = hb_fifo_get( pv->subtitle_queue );
504         if( subtitles )
505         {
506             ApplySub( job, buf_tmp_in, &subtitles );
507         }
508     }
509
510     /* Apply crop/scale if specified */
511     if( buf_tmp_in && pv->context )
512     {
513         avpicture_fill( &pv->pic_tmp_in, buf_tmp_in->data,
514                         PIX_FMT_YUV420P,
515                         title->width, title->height );
516
517         avpicture_fill( &pv->pic_tmp_out, buf_render->data,
518                         PIX_FMT_YUV420P,
519                         job->width, job->height );
520
521         // Crop; this alters the pointer to the data to point to the correct place for cropped frame
522         av_picture_crop( &pv->pic_tmp_crop, &pv->pic_tmp_in, PIX_FMT_YUV420P,
523                          job->crop[0], job->crop[2] );
524
525         // Scale pic_crop into pic_render according to the context set up in renderInit
526         sws_scale(pv->context,
527                   pv->pic_tmp_crop.data, pv->pic_tmp_crop.linesize,
528                   0, title->height - (job->crop[0] + job->crop[1]),
529                   pv->pic_tmp_out.data,  pv->pic_tmp_out.linesize);
530
531         hb_buffer_copy_settings( buf_render, buf_tmp_in );
532
533         buf_tmp_in = buf_render;
534     }
535
536     /* Set output to render buffer */
537     (*buf_out) = buf_render;
538
539     if( buf_tmp_in == NULL )
540     {
541         /* Teardown and cleanup buffers if we are emitting NULL */
542         if( buf_in && *buf_in )
543         {
544             hb_buffer_close( buf_in );
545             *buf_in = NULL;
546         }
547         if( buf_out && *buf_out )
548         {
549             hb_buffer_close( buf_out );
550             *buf_out = NULL;
551         }
552     }
553     else if( buf_tmp_in != buf_render )
554     {
555         /* Copy temporary results and settings into render buffer */
556         memcpy( buf_render->data, buf_tmp_in->data, buf_render->size );
557         hb_buffer_copy_settings( buf_render, buf_tmp_in );
558     }
559
560     if (*buf_out )
561     {
562         hb_fifo_push( pv->delay_queue, *buf_out );
563         *buf_out = NULL;
564     }
565
566     /*
567      * Keep the last three frames in our queue, this ensures that we have the last
568      * two always in there should we need to rewrite the durations on them.
569      */
570
571     if( hb_fifo_size( pv->delay_queue ) >= 4 )
572     {
573         *buf_out = hb_fifo_get( pv->delay_queue );
574     }
575
576     if( *buf_out )
577     {
578         /* The current frame exists. That means it hasn't been dropped by a filter.
579            Make it accessible as ivtc_buffer so we can edit its duration if needed. */
580         ivtc_buffer = *buf_out;
581
582         if( pv->lost_time[3] > 0 )
583         {
584             /*
585              * A frame's been dropped earlier by VFR detelecine.
586              * Gotta make up the lost time. This will also
587              * slow down the video.
588              * The dropped frame's has to be accounted for, so
589              * divvy it up amongst the 4 frames left behind.
590              * This is what the delay_queue is for;
591              * telecined sequences start 2 frames before
592              * the dropped frame, so to slow down the right
593              * ones you need a 2 frame delay between
594              * reading input and writing output.
595              */
596
597             /* We want to extend the outputted frame's duration by the value
598               stored in the 4th slot of the lost_time array. Because we need
599               to adjust all the values in the array so they're contiguous,
600               extend the duration inside the array first, before applying
601               it to the current frame buffer. */
602             pv->last_stop[3] += pv->lost_time[3];
603
604             /* Log how much time has been added back in to the video. */
605             pv->total_gained_time += pv->lost_time[3];
606
607             /* We've pulled the 4th value from the lost_time array
608                and added it to the last_stop array's 4th slot. Now, rotate the
609                 lost_time array so the 4th slot now holds the 3rd's value, and
610                so on down the line, and set the 0 index to a value of 0. */
611             int i;
612             for( i=2; i >=  0; i--)
613             {
614                 pv->lost_time[i+1] = pv->lost_time[i];
615             }
616             pv->lost_time[0] = 0;
617
618             /* Log how many frames have had their durations extended. */
619             pv->extended_frames++;
620         }
621
622         /* We can't use the given time stamps. Previous frames
623            might already have been extended, throwing off the
624            raw values fed to render.c. Instead, their
625            stop and start times are stored in arrays.
626            The 4th cached frame will be the to use.
627            If it needed its duration extended to make up
628            lost time, it will have happened above. */
629         ivtc_buffer->start = pv->last_start[3];
630         ivtc_buffer->stop = pv->last_stop[3];
631
632         /* Set the 3rd cached frame to start when this one stops,
633            and so on down the line. If any of them need to be
634            extended as well to make up lost time, it'll be handled
635            on the next loop through the renderer.  */
636         int i;
637         for (i = 2; i >= 0; i--)
638         {
639             int temp_duration = pv->last_stop[i] - pv->last_start[i];
640             pv->last_start[i] = pv->last_stop[i+1];
641             pv->last_stop[i] = pv->last_start[i] + temp_duration;
642         }
643
644         /* If we have a pending chapter mark and this frame is at
645            or after the time of the mark, mark this frame & clear
646            our pending mark. */
647         if( pv->chapter_time && pv->chapter_time <= ivtc_buffer->start )
648         {
649             ivtc_buffer->new_chap = pv->chapter_val;
650             pv->chapter_time = 0;
651         }
652
653     }
654
655     if ( buf_out && *buf_out && job->cfr )
656     {
657         adjust_frame_rate( pv, buf_out );
658     }
659     return HB_WORK_OK;
660 }
661
662 void renderClose( hb_work_object_t * w )
663 {
664     hb_work_private_t * pv = w->private_data;
665
666     if ( pv->job->cfr )
667     {
668         hb_log("render: %d frames output, %d dropped and %d duped for CFR/PFR",
669                pv->count_frames, pv->drops, pv->dups );
670     }
671
672     hb_interjob_t * interjob = hb_interjob_get( w->private_data->job->h );
673     
674     /* Preserve dropped frame count for more accurate framerates in 2nd passes. */
675     interjob->render_dropped = pv->dropped_frames;
676
677     hb_log("render: lost time: %"PRId64" (%i frames)", pv->total_lost_time, pv->dropped_frames);
678     hb_log("render: gained time: %"PRId64" (%i frames) (%"PRId64" not accounted for)", pv->total_gained_time, pv->extended_frames, pv->total_lost_time - pv->total_gained_time);
679     if (pv->dropped_frames)
680         hb_log("render: average dropped frame duration: %"PRId64, (pv->total_lost_time / pv->dropped_frames) );
681
682     /* Cleanup subtitle queue */
683     if( pv->subtitle_queue )
684     {
685         hb_fifo_close( &pv->subtitle_queue );
686     }
687
688     if( pv->delay_queue )
689     {
690         hb_fifo_close( &pv->delay_queue );
691     }
692
693     /* Cleanup render work structure */
694     free( pv );
695     w->private_data = NULL;
696 }
697
698 int renderInit( hb_work_object_t * w, hb_job_t * job )
699 {
700     /* Allocate new private work object */
701     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
702     pv->job = job;
703     w->private_data = pv;
704     uint32_t    swsflags;
705
706     swsflags = SWS_LANCZOS | SWS_ACCURATE_RND;
707
708     /* Get title and title size */
709     hb_title_t * title = job->title;
710
711     /* If crop or scale is specified, setup rescale context */
712     if( job->crop[0] || job->crop[1] || job->crop[2] || job->crop[3] ||
713         job->width != title->width || job->height != title->height )
714     {
715         pv->context = sws_getContext(title->width  - (job->crop[2] + job->crop[3]),
716                                      title->height - (job->crop[0] + job->crop[1]),
717                                      PIX_FMT_YUV420P,
718                                      job->width, job->height, PIX_FMT_YUV420P,
719                                      swsflags, NULL, NULL, NULL);
720     }
721
722     /* Setup FIFO queue for subtitle cache */
723     pv->subtitle_queue = hb_fifo_init( 8 );
724     pv->delay_queue = hb_fifo_init( 8 );
725
726     /* VFR IVTC needs a bunch of time-keeping variables to track
727       how many frames are dropped, how many are extended, what the
728       last 4 start and stop times were (so they can be modified),
729       how much time has been lost and gained overall, how much time
730       the latest 4 frames should be extended by, and where chapter
731       markers are (so they can be saved if their frames are dropped.) */
732     pv->dropped_frames = 0;
733     pv->extended_frames = 0;
734     pv->last_start[0] = 0;
735     pv->last_stop[0] = 0;
736     pv->total_lost_time = 0;
737     pv->total_gained_time = 0;
738     pv->lost_time[0] = 0; pv->lost_time[1] = 0; pv->lost_time[2] = 0; pv->lost_time[3] = 0;
739     pv->chapter_time = 0;
740     pv->chapter_val  = 0;
741
742     pv->frame_rate = (double)job->vrate_base * (1./300.);
743
744     /* Setup filters */
745     /* TODO: Move to work.c? */
746     if( job->filters )
747     {
748         int filter_count = hb_list_count( job->filters );
749         int i;
750
751         for( i = 0; i < filter_count; i++ )
752         {
753             hb_filter_object_t * filter = hb_list_item( job->filters, i );
754
755             if( !filter ) continue;
756
757             filter->private_data = filter->init( PIX_FMT_YUV420P,
758                                                  title->width,
759                                                  title->height,
760                                                  filter->settings );
761         }
762     }
763
764     return 0;
765 }