OSDN Git Service

MacGui: here's the .nib part of the r573 commit, which didn't take.
[handbrake-jp/handbrake-jp-git.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.m0k.org/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include "hb.h"
8
9 #include "ffmpeg/avcodec.h"
10
11 struct hb_work_private_s
12 {
13     hb_job_t * job;
14
15     ImgReSampleContext * context;
16     AVPicture            pic_raw;
17     AVPicture            pic_deint;
18     AVPicture            pic_render;
19     hb_buffer_t        * buf_deint;
20 };
21
22 int  renderInit( hb_work_object_t *, hb_job_t * );
23 int  renderWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
24 void renderClose( hb_work_object_t * );
25
26 hb_work_object_t hb_render =
27 {   
28     WORK_RENDER,
29     "Renderer",
30     renderInit,
31     renderWork,
32     renderClose
33 };
34
35 static void ApplySub( hb_job_t * job, hb_buffer_t * buf,
36                       hb_buffer_t ** _sub )
37 {
38     hb_buffer_t * sub = *_sub;
39     hb_title_t * title = job->title;
40     int i, j, offset_top, offset_left;
41     uint8_t * lum, * alpha, * out;
42
43     if( !sub )
44     {
45         return;
46     }
47
48     /* If necessary, move the subtitle so it is not in a cropped zone.
49        When it won't fit, we center it so we loose as much on both ends.
50        Otherwise we try to leave a 20px margin around it. */
51
52     if( sub->height > title->height - job->crop[0] - job->crop[1] - 40 )
53         offset_top = job->crop[0] + ( title->height - job->crop[0] -
54                 job->crop[1] - sub->height ) / 2;
55     else if( sub->y < job->crop[0] + 20 )
56         offset_top = job->crop[0] + 20;
57     else if( sub->y > title->height - job->crop[1] - 20 - sub->height )
58         offset_top = title->height - job->crop[1] - 20 - sub->height;
59     else
60         offset_top = sub->y;
61
62     if( sub->width > title->width - job->crop[2] - job->crop[3] - 40 )
63         offset_left = job->crop[2] + ( title->width - job->crop[2] -
64                 job->crop[3] - sub->width ) / 2;
65     else if( sub->x < job->crop[2] + 20 )
66         offset_left = job->crop[2] + 20;
67     else if( sub->x > title->width - job->crop[3] - 20 - sub->width )
68         offset_left = title->width - job->crop[3] - 20 - sub->width;
69     else
70         offset_left = sub->x;
71
72     lum   = sub->data;
73     alpha = lum + sub->width * sub->height;
74     out   = buf->data + offset_top * title->width + offset_left;
75
76     for( i = 0; i < sub->height; i++ )
77     {
78         if( offset_top + i >= 0 && offset_top + i < title->height )
79         {
80             for( j = 0; j < sub->width; j++ )
81             {
82                 if( offset_left + j >= 0 && offset_left + j < title->width )
83                 {
84                     out[j] = ( (uint16_t) out[j] * ( 16 - (uint16_t) alpha[j] ) +
85                                (uint16_t) lum[j] * (uint16_t) alpha[j] ) >> 4;
86                 }
87             }
88         }
89
90         lum   += sub->width;
91         alpha += sub->width;
92         out   += title->width;
93     }
94
95     hb_buffer_close( _sub );
96 }
97
98 int renderWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
99                 hb_buffer_t ** buf_out )
100 {
101     hb_work_private_t * pv = w->private_data;
102     hb_job_t   * job   = pv->job;
103     hb_title_t * title = job->title;
104     hb_buffer_t * in = *buf_in, * buf;
105
106     if(!in->data)
107     {
108         /* If the input buffer is end of stream, send out an empty one to the next stage as well. */
109         *buf_out = hb_buffer_init(0);
110         return HB_WORK_OK;
111     }
112
113     avpicture_fill( &pv->pic_raw, in->data, PIX_FMT_YUV420P,
114                     title->width, title->height );
115
116     buf        = hb_buffer_init( 3 * job->width * job->height / 2 );
117     buf->start = in->start;
118     buf->stop  = in->stop;
119
120     if( job->deinterlace && pv->context )
121     {
122         avpicture_fill( &pv->pic_render, buf->data, PIX_FMT_YUV420P,
123                         job->width, job->height );
124         avpicture_deinterlace( &pv->pic_deint, &pv->pic_raw,
125                                PIX_FMT_YUV420P, title->width,
126                                title->height );
127         ApplySub( job, pv->buf_deint, &in->sub );
128         img_resample( pv->context, &pv->pic_render, &pv->pic_deint );
129     }
130     else if( job->deinterlace )
131     {
132         avpicture_fill( &pv->pic_deint, buf->data, PIX_FMT_YUV420P,
133                         job->width, job->height );
134         avpicture_deinterlace( &pv->pic_deint, &pv->pic_raw,
135                                PIX_FMT_YUV420P, title->width,
136                                title->height );
137         ApplySub( job, buf, &in->sub );
138     }
139     else if( pv->context )
140     {
141         ApplySub( job, in, &in->sub );
142         avpicture_fill( &pv->pic_render, buf->data, PIX_FMT_YUV420P,
143                         job->width, job->height );
144         img_resample( pv->context, &pv->pic_render, &pv->pic_raw );
145     }
146     else
147     {
148         hb_buffer_close( &buf );
149         ApplySub( job, in, &in->sub );
150         buf      = in;
151         *buf_in  = NULL;
152     }
153
154     (*buf_out) = buf;
155
156     return HB_WORK_OK;
157 }
158
159 void renderClose( hb_work_object_t * w )
160 {
161     hb_work_private_t * pv = w->private_data;
162     
163     free( pv );
164     w->private_data = NULL;
165 }
166
167 int renderInit( hb_work_object_t * w, hb_job_t * job )
168 {
169     hb_title_t * title;
170     
171     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
172     w->private_data = pv;
173
174     title = job->title;
175
176     pv->job = job;
177
178     if( job->crop[0] || job->crop[1] || job->crop[2] || job->crop[3] ||
179         job->width != title->width || job->height != title->height )
180     {
181         pv->context = img_resample_full_init(
182             job->width, job->height, title->width, title->height,
183             job->crop[0], job->crop[1], job->crop[2], job->crop[3],
184             0, 0, 0, 0 );
185     }
186
187     if( job->deinterlace )
188     {
189         /* Allocate a constant buffer used for deinterlacing */
190         pv->buf_deint = hb_buffer_init( 3 * title->width *
191                                        title->height / 2 );
192         avpicture_fill( &pv->pic_deint, pv->buf_deint->data,
193                         PIX_FMT_YUV420P, title->width, title->height );
194     }
195
196     return 0;
197 }