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 AVPixelFormat 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
00163 int ff_inplace_start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
00164 {
00165 AVFilterLink *outlink = inlink->dst->outputs[0];
00166 AVFilterBufferRef *outpicref = NULL, *for_next_filter;
00167 int ret = 0;
00168
00169 if (inpicref->perms & AV_PERM_WRITE) {
00170 outpicref = avfilter_ref_buffer(inpicref, ~0);
00171 if (!outpicref)
00172 return AVERROR(ENOMEM);
00173 } else {
00174 outpicref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
00175 if (!outpicref)
00176 return AVERROR(ENOMEM);
00177
00178 avfilter_copy_buffer_ref_props(outpicref, inpicref);
00179 outpicref->video->w = outlink->w;
00180 outpicref->video->h = outlink->h;
00181 }
00182
00183 for_next_filter = avfilter_ref_buffer(outpicref, ~0);
00184 if (for_next_filter)
00185 ret = ff_start_frame(outlink, for_next_filter);
00186 else
00187 ret = AVERROR(ENOMEM);
00188
00189 if (ret < 0) {
00190 avfilter_unref_bufferp(&outpicref);
00191 return ret;
00192 }
00193
00194 outlink->out_buf = outpicref;
00195 return 0;
00196 }
00197
00198 static int default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
00199 {
00200 AVFilterLink *outlink = NULL;
00201
00202 if (inlink->dst->nb_outputs)
00203 outlink = inlink->dst->outputs[0];
00204
00205 if (outlink && (inlink->dstpad->start_frame || inlink->dstpad->end_frame || inlink->dstpad->draw_slice)) {
00206 AVFilterBufferRef *buf_out;
00207 outlink->out_buf = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
00208 if (!outlink->out_buf)
00209 return AVERROR(ENOMEM);
00210
00211 avfilter_copy_buffer_ref_props(outlink->out_buf, picref);
00212 outlink->out_buf->video->w = outlink->w;
00213 outlink->out_buf->video->h = outlink->h;
00214 buf_out = avfilter_ref_buffer(outlink->out_buf, ~0);
00215 if (!buf_out)
00216 return AVERROR(ENOMEM);
00217
00218 return ff_start_frame(outlink, buf_out);
00219 }
00220 return 0;
00221 }
00222
00223 static void clear_link(AVFilterLink *link)
00224 {
00225 avfilter_unref_bufferp(&link->cur_buf);
00226 avfilter_unref_bufferp(&link->src_buf);
00227 avfilter_unref_bufferp(&link->out_buf);
00228 link->cur_buf_copy = NULL;
00229 }
00230
00231
00232
00233 int ff_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
00234 {
00235 int (*start_frame)(AVFilterLink *, AVFilterBufferRef *);
00236 AVFilterPad *src = link->srcpad;
00237 AVFilterPad *dst = link->dstpad;
00238 int ret, perms;
00239 AVFilterCommand *cmd= link->dst->command_queue;
00240 int64_t pts;
00241
00242 FF_TPRINTF_START(NULL, start_frame); ff_tlog_link(NULL, link, 0); ff_tlog(NULL, " "); ff_tlog_ref(NULL, picref, 1);
00243
00244 if (strcmp(link->dst->filter->name, "scale")) {
00245 av_assert1(picref->format == link->format);
00246 av_assert1(picref->video->w == link->w);
00247 av_assert1(picref->video->h == link->h);
00248 }
00249
00250 if (link->closed) {
00251 avfilter_unref_buffer(picref);
00252 return AVERROR_EOF;
00253 }
00254
00255 if (!(start_frame = dst->start_frame))
00256 start_frame = default_start_frame;
00257
00258 av_assert1((picref->perms & src->min_perms) == src->min_perms);
00259 picref->perms &= ~ src->rej_perms;
00260 perms = picref->perms;
00261
00262 if (picref->linesize[0] < 0)
00263 perms |= AV_PERM_NEG_LINESIZES;
00264
00265 if ((dst->min_perms & perms) != dst->min_perms || dst->rej_perms & perms) {
00266 av_log(link->dst, AV_LOG_DEBUG,
00267 "frame copy needed (have perms %x, need %x, reject %x)\n",
00268 picref->perms,
00269 link->dstpad->min_perms, link->dstpad->rej_perms);
00270
00271 link->cur_buf = ff_get_video_buffer(link, dst->min_perms, link->w, link->h);
00272 if (!link->cur_buf) {
00273 avfilter_unref_bufferp(&picref);
00274 return AVERROR(ENOMEM);
00275 }
00276
00277 link->src_buf = picref;
00278 avfilter_copy_buffer_ref_props(link->cur_buf, link->src_buf);
00279
00280
00281 if (av_pix_fmt_desc_get(link->format)->flags & PIX_FMT_PAL)
00282 memcpy(link->cur_buf->data[1], link->src_buf-> data[1], AVPALETTE_SIZE);
00283 }
00284 else
00285 link->cur_buf = picref;
00286
00287 link->cur_buf_copy = link->cur_buf;
00288
00289 while(cmd && cmd->time <= picref->pts * av_q2d(link->time_base)){
00290 av_log(link->dst, AV_LOG_DEBUG,
00291 "Processing command time:%f command:%s arg:%s\n",
00292 cmd->time, cmd->command, cmd->arg);
00293 avfilter_process_command(link->dst, cmd->command, cmd->arg, 0, 0, cmd->flags);
00294 ff_command_queue_pop(link->dst);
00295 cmd= link->dst->command_queue;
00296 }
00297 pts = link->cur_buf->pts;
00298 ret = start_frame(link, link->cur_buf);
00299 ff_update_link_current_pts(link, pts);
00300 if (ret < 0)
00301 clear_link(link);
00302 else
00303
00304
00305 av_assert1(link->cur_buf_copy->buf->refcount > 0);
00306
00307 return ret;
00308 }
00309
00310 static int default_end_frame(AVFilterLink *inlink)
00311 {
00312 AVFilterLink *outlink = NULL;
00313
00314 if (inlink->dst->nb_outputs)
00315 outlink = inlink->dst->outputs[0];
00316
00317 if (outlink) {
00318 if (inlink->dstpad->filter_frame) {
00319 int ret = inlink->dstpad->filter_frame(inlink, inlink->cur_buf);
00320 inlink->cur_buf = NULL;
00321 return ret;
00322 } else if (inlink->dstpad->start_frame || inlink->dstpad->end_frame || inlink->dstpad->draw_slice){
00323 return ff_end_frame(outlink);
00324 } else {
00325 int ret = ff_filter_frame(outlink, inlink->cur_buf);
00326 inlink->cur_buf = NULL;
00327 return ret;
00328 }
00329 }
00330 return 0;
00331 }
00332
00333 int ff_end_frame(AVFilterLink *link)
00334 {
00335 int (*end_frame)(AVFilterLink *);
00336 int ret;
00337
00338 if (!(end_frame = link->dstpad->end_frame))
00339 end_frame = default_end_frame;
00340
00341 ret = end_frame(link);
00342
00343 clear_link(link);
00344
00345 return ret;
00346 }
00347
00348 static int default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
00349 {
00350 AVFilterLink *outlink = NULL;
00351
00352 if (inlink->dst->nb_outputs)
00353 outlink = inlink->dst->outputs[0];
00354
00355 if (outlink && (inlink->dstpad->start_frame || inlink->dstpad->end_frame || inlink->dstpad->draw_slice))
00356 return ff_draw_slice(outlink, y, h, slice_dir);
00357 return 0;
00358 }
00359
00360 int ff_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
00361 {
00362 uint8_t *src[4], *dst[4];
00363 int i, j, vsub, ret;
00364 int (*draw_slice)(AVFilterLink *, int, int, int);
00365
00366 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);
00367
00368
00369 if (link->src_buf) {
00370 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
00371 vsub = desc->log2_chroma_h;
00372
00373 for (i = 0; i < 4; i++) {
00374 if (link->src_buf->data[i]) {
00375 src[i] = link->src_buf-> data[i] +
00376 (y >> (i==1 || i==2 ? vsub : 0)) * link->src_buf-> linesize[i];
00377 dst[i] = link->cur_buf_copy->data[i] +
00378 (y >> (i==1 || i==2 ? vsub : 0)) * link->cur_buf_copy->linesize[i];
00379 } else
00380 src[i] = dst[i] = NULL;
00381 }
00382
00383 for (i = 0; i < 4; i++) {
00384 int planew =
00385 av_image_get_linesize(link->format, link->cur_buf_copy->video->w, i);
00386
00387 if (!src[i]) continue;
00388
00389 for (j = 0; j < h >> (i==1 || i==2 ? vsub : 0); j++) {
00390 memcpy(dst[i], src[i], planew);
00391 src[i] += link->src_buf->linesize[i];
00392 dst[i] += link->cur_buf_copy->linesize[i];
00393 }
00394 }
00395 }
00396
00397 if (!(draw_slice = link->dstpad->draw_slice))
00398 draw_slice = default_draw_slice;
00399 ret = draw_slice(link, y, h, slice_dir);
00400 if (ret < 0)
00401 clear_link(link);
00402 else
00403
00404
00405 av_assert1(link->cur_buf_copy->buf->refcount > 0);
00406 return ret;
00407 }