00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <string.h>
00024 #include <stdio.h>
00025
00026 #include "libavutil/avassert.h"
00027 #include "libavutil/imgutils.h"
00028 #include "libavutil/mem.h"
00029
00030 #include "avfilter.h"
00031 #include "internal.h"
00032 #include "video.h"
00033
00034 AVFilterBufferRef *ff_null_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
00035 {
00036 return ff_get_video_buffer(link->dst->outputs[0], perms, w, h);
00037 }
00038
00039 AVFilterBufferRef *ff_default_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
00040 {
00041 int linesize[4];
00042 uint8_t *data[4];
00043 int i;
00044 AVFilterBufferRef *picref = NULL;
00045 AVFilterPool *pool = link->pool;
00046 int full_perms = AV_PERM_READ | AV_PERM_WRITE | AV_PERM_PRESERVE |
00047 AV_PERM_REUSE | AV_PERM_REUSE2 | AV_PERM_ALIGN;
00048
00049 av_assert1(!(perms & ~(full_perms | AV_PERM_NEG_LINESIZES)));
00050
00051 if (pool) {
00052 for (i = 0; i < POOL_SIZE; i++) {
00053 picref = pool->pic[i];
00054 if (picref && picref->buf->format == link->format && picref->buf->w == w && picref->buf->h == h) {
00055 AVFilterBuffer *pic = picref->buf;
00056 pool->pic[i] = NULL;
00057 pool->count--;
00058 av_assert0(!picref->video->qp_table);
00059 picref->video->w = w;
00060 picref->video->h = h;
00061 picref->perms = full_perms;
00062 picref->format = link->format;
00063 pic->refcount = 1;
00064 memcpy(picref->data, pic->data, sizeof(picref->data));
00065 memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize));
00066 pool->refcount++;
00067 return picref;
00068 }
00069 }
00070 } else {
00071 pool = link->pool = av_mallocz(sizeof(AVFilterPool));
00072 pool->refcount = 1;
00073 }
00074
00075
00076 if ((i = av_image_alloc(data, linesize, w, h, link->format, 32)) < 0)
00077 return NULL;
00078
00079 picref = avfilter_get_video_buffer_ref_from_arrays(data, linesize,
00080 full_perms, w, h, link->format);
00081 if (!picref) {
00082 av_free(data[0]);
00083 return NULL;
00084 }
00085
00086 memset(data[0], 128, i);
00087
00088 picref->buf->priv = pool;
00089 picref->buf->free = NULL;
00090 pool->refcount++;
00091
00092 return picref;
00093 }
00094
00095 AVFilterBufferRef *
00096 avfilter_get_video_buffer_ref_from_arrays(uint8_t * const data[4], const int linesize[4], int perms,
00097 int w, int h, enum PixelFormat format)
00098 {
00099 AVFilterBuffer *pic = av_mallocz(sizeof(AVFilterBuffer));
00100 AVFilterBufferRef *picref = av_mallocz(sizeof(AVFilterBufferRef));
00101
00102 if (!pic || !picref)
00103 goto fail;
00104
00105 picref->buf = pic;
00106 picref->buf->free = ff_avfilter_default_free_buffer;
00107 if (!(picref->video = av_mallocz(sizeof(AVFilterBufferRefVideoProps))))
00108 goto fail;
00109
00110 pic->w = picref->video->w = w;
00111 pic->h = picref->video->h = h;
00112
00113
00114 picref->perms = perms | AV_PERM_READ;
00115
00116 pic->refcount = 1;
00117 picref->type = AVMEDIA_TYPE_VIDEO;
00118 pic->format = picref->format = format;
00119
00120 memcpy(pic->data, data, 4*sizeof(data[0]));
00121 memcpy(pic->linesize, linesize, 4*sizeof(linesize[0]));
00122 memcpy(picref->data, pic->data, sizeof(picref->data));
00123 memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize));
00124
00125 pic-> extended_data = pic->data;
00126 picref->extended_data = picref->data;
00127
00128 picref->pts = AV_NOPTS_VALUE;
00129
00130 return picref;
00131
00132 fail:
00133 if (picref && picref->video)
00134 av_free(picref->video);
00135 av_free(picref);
00136 av_free(pic);
00137 return NULL;
00138 }
00139
00140 AVFilterBufferRef *ff_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
00141 {
00142 AVFilterBufferRef *ret = NULL;
00143
00144 av_unused char buf[16];
00145 FF_TPRINTF_START(NULL, get_video_buffer); ff_tlog_link(NULL, link, 0);
00146 ff_tlog(NULL, " perms:%s w:%d h:%d\n", ff_get_ref_perms_string(buf, sizeof(buf), perms), w, h);
00147
00148 if (link->dstpad->get_video_buffer)
00149 ret = link->dstpad->get_video_buffer(link, perms, w, h);
00150
00151 if (!ret)
00152 ret = ff_default_get_video_buffer(link, perms, w, h);
00153
00154 if (ret)
00155 ret->type = AVMEDIA_TYPE_VIDEO;
00156
00157 FF_TPRINTF_START(NULL, get_video_buffer); ff_tlog_link(NULL, link, 0); ff_tlog(NULL, " returning "); ff_tlog_ref(NULL, ret, 1);
00158
00159 return ret;
00160 }
00161
00162 int ff_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
00163 {
00164 AVFilterBufferRef *buf_out = avfilter_ref_buffer(picref, ~0);
00165 if (!buf_out)
00166 return AVERROR(ENOMEM);
00167 return ff_start_frame(link->dst->outputs[0], buf_out);
00168 }
00169
00170
00171 int ff_inplace_start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
00172 {
00173 AVFilterLink *outlink = inlink->dst->outputs[0];
00174 AVFilterBufferRef *outpicref = NULL, *for_next_filter;
00175 int ret = 0;
00176
00177 if (inpicref->perms & AV_PERM_WRITE) {
00178 outpicref = avfilter_ref_buffer(inpicref, ~0);
00179 if (!outpicref)
00180 return AVERROR(ENOMEM);
00181 } else {
00182 outpicref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
00183 if (!outpicref)
00184 return AVERROR(ENOMEM);
00185
00186 avfilter_copy_buffer_ref_props(outpicref, inpicref);
00187 outpicref->video->w = outlink->w;
00188 outpicref->video->h = outlink->h;
00189 }
00190
00191 for_next_filter = avfilter_ref_buffer(outpicref, ~0);
00192 if (for_next_filter)
00193 ret = ff_start_frame(outlink, for_next_filter);
00194 else
00195 ret = AVERROR(ENOMEM);
00196
00197 if (ret < 0) {
00198 avfilter_unref_bufferp(&outpicref);
00199 return ret;
00200 }
00201
00202 outlink->out_buf = outpicref;
00203 return 0;
00204 }
00205
00206 static int default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
00207 {
00208 AVFilterLink *outlink = NULL;
00209
00210 if (inlink->dst->nb_outputs)
00211 outlink = inlink->dst->outputs[0];
00212
00213 if (outlink) {
00214 AVFilterBufferRef *buf_out;
00215 outlink->out_buf = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
00216 if (!outlink->out_buf)
00217 return AVERROR(ENOMEM);
00218
00219 avfilter_copy_buffer_ref_props(outlink->out_buf, picref);
00220 outlink->out_buf->video->w = outlink->w;
00221 outlink->out_buf->video->h = outlink->h;
00222 buf_out = avfilter_ref_buffer(outlink->out_buf, ~0);
00223 if (!buf_out)
00224 return AVERROR(ENOMEM);
00225
00226 return ff_start_frame(outlink, buf_out);
00227 }
00228 return 0;
00229 }
00230
00231 static void clear_link(AVFilterLink *link)
00232 {
00233 avfilter_unref_bufferp(&link->cur_buf);
00234 avfilter_unref_bufferp(&link->src_buf);
00235 avfilter_unref_bufferp(&link->out_buf);
00236 link->cur_buf_copy = NULL;
00237 }
00238
00239
00240
00241 int ff_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
00242 {
00243 int (*start_frame)(AVFilterLink *, AVFilterBufferRef *);
00244 AVFilterPad *src = link->srcpad;
00245 AVFilterPad *dst = link->dstpad;
00246 int ret, perms;
00247 AVFilterCommand *cmd= link->dst->command_queue;
00248 int64_t pts;
00249
00250 FF_TPRINTF_START(NULL, start_frame); ff_tlog_link(NULL, link, 0); ff_tlog(NULL, " "); ff_tlog_ref(NULL, picref, 1);
00251
00252 av_assert1(picref->format == link->format);
00253 av_assert1(picref->video->w == link->w);
00254 av_assert1(picref->video->h == link->h);
00255
00256 if (link->closed) {
00257 avfilter_unref_buffer(picref);
00258 return AVERROR_EOF;
00259 }
00260
00261 if (!(start_frame = dst->start_frame))
00262 start_frame = default_start_frame;
00263
00264 av_assert1((picref->perms & src->min_perms) == src->min_perms);
00265 picref->perms &= ~ src->rej_perms;
00266 perms = picref->perms;
00267
00268 if (picref->linesize[0] < 0)
00269 perms |= AV_PERM_NEG_LINESIZES;
00270
00271 if ((dst->min_perms & perms) != dst->min_perms || dst->rej_perms & perms) {
00272 av_log(link->dst, AV_LOG_DEBUG,
00273 "frame copy needed (have perms %x, need %x, reject %x)\n",
00274 picref->perms,
00275 link->dstpad->min_perms, link->dstpad->rej_perms);
00276
00277 link->cur_buf = ff_get_video_buffer(link, dst->min_perms, link->w, link->h);
00278 if (!link->cur_buf) {
00279 avfilter_unref_bufferp(&picref);
00280 return AVERROR(ENOMEM);
00281 }
00282
00283 link->src_buf = picref;
00284 avfilter_copy_buffer_ref_props(link->cur_buf, link->src_buf);
00285
00286
00287 if (av_pix_fmt_descriptors[link->format].flags & PIX_FMT_PAL)
00288 memcpy(link->cur_buf->data[1], link->src_buf-> data[1], AVPALETTE_SIZE);
00289 }
00290 else
00291 link->cur_buf = picref;
00292
00293 link->cur_buf_copy = link->cur_buf;
00294
00295 while(cmd && cmd->time <= picref->pts * av_q2d(link->time_base)){
00296 av_log(link->dst, AV_LOG_DEBUG,
00297 "Processing command time:%f command:%s arg:%s\n",
00298 cmd->time, cmd->command, cmd->arg);
00299 avfilter_process_command(link->dst, cmd->command, cmd->arg, 0, 0, cmd->flags);
00300 ff_command_queue_pop(link->dst);
00301 cmd= link->dst->command_queue;
00302 }
00303 pts = link->cur_buf->pts;
00304 ret = start_frame(link, link->cur_buf);
00305 ff_update_link_current_pts(link, pts);
00306 if (ret < 0)
00307 clear_link(link);
00308 else
00309
00310
00311 av_assert1(link->cur_buf_copy->buf->refcount > 0);
00312
00313 return ret;
00314 }
00315
00316 int ff_null_end_frame(AVFilterLink *link)
00317 {
00318 return ff_end_frame(link->dst->outputs[0]);
00319 }
00320
00321 static int default_end_frame(AVFilterLink *inlink)
00322 {
00323 AVFilterLink *outlink = NULL;
00324
00325 if (inlink->dst->nb_outputs)
00326 outlink = inlink->dst->outputs[0];
00327
00328 if (outlink) {
00329 return ff_end_frame(outlink);
00330 }
00331 return 0;
00332 }
00333
00334 int ff_end_frame(AVFilterLink *link)
00335 {
00336 int (*end_frame)(AVFilterLink *);
00337 int ret;
00338
00339 if (!(end_frame = link->dstpad->end_frame))
00340 end_frame = default_end_frame;
00341
00342 ret = end_frame(link);
00343
00344 clear_link(link);
00345
00346 return ret;
00347 }
00348
00349 int ff_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
00350 {
00351 return ff_draw_slice(link->dst->outputs[0], y, h, slice_dir);
00352 }
00353
00354 static int default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
00355 {
00356 AVFilterLink *outlink = NULL;
00357
00358 if (inlink->dst->nb_outputs)
00359 outlink = inlink->dst->outputs[0];
00360
00361 if (outlink)
00362 return ff_draw_slice(outlink, y, h, slice_dir);
00363 return 0;
00364 }
00365
00366 int ff_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
00367 {
00368 uint8_t *src[4], *dst[4];
00369 int i, j, vsub, ret;
00370 int (*draw_slice)(AVFilterLink *, int, int, int);
00371
00372 FF_TPRINTF_START(NULL, draw_slice); ff_tlog_link(NULL, link, 0); ff_tlog(NULL, " y:%d h:%d dir:%d\n", y, h, slice_dir);
00373
00374
00375 if (link->src_buf) {
00376 vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h;
00377
00378 for (i = 0; i < 4; i++) {
00379 if (link->src_buf->data[i]) {
00380 src[i] = link->src_buf-> data[i] +
00381 (y >> (i==1 || i==2 ? vsub : 0)) * link->src_buf-> linesize[i];
00382 dst[i] = link->cur_buf_copy->data[i] +
00383 (y >> (i==1 || i==2 ? vsub : 0)) * link->cur_buf_copy->linesize[i];
00384 } else
00385 src[i] = dst[i] = NULL;
00386 }
00387
00388 for (i = 0; i < 4; i++) {
00389 int planew =
00390 av_image_get_linesize(link->format, link->cur_buf_copy->video->w, i);
00391
00392 if (!src[i]) continue;
00393
00394 for (j = 0; j < h >> (i==1 || i==2 ? vsub : 0); j++) {
00395 memcpy(dst[i], src[i], planew);
00396 src[i] += link->src_buf->linesize[i];
00397 dst[i] += link->cur_buf_copy->linesize[i];
00398 }
00399 }
00400 }
00401
00402 if (!(draw_slice = link->dstpad->draw_slice))
00403 draw_slice = default_draw_slice;
00404 ret = draw_slice(link, y, h, slice_dir);
00405 if (ret < 0)
00406 clear_link(link);
00407 else
00408
00409
00410 av_assert1(link->cur_buf_copy->buf->refcount > 0);
00411 return ret;
00412 }