Unlike av_frame_is_writable(), it uses the link's alloc callback, making direct rendering possible. The code comes from ff_filter_frame_framed(), moved with mostly trivial changes.
Unified · Split
| @@ -1107,49 +1107,12 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) · 1106 unmodified lines | |||
| 1107 | if (!(filter_frame = dst->filter_frame)) | 1107 | if (!(filter_frame = dst->filter_frame)) |
| 1108 | filter_frame = default_filter_frame; | 1108 | filter_frame = default_filter_frame; |
| 1109 | 1109 | ||
| 1110 | /* copy the frame if needed */ | 1110 | if (dst->needs_writable) { |
| 1111 | if (dst->needs_writable && !av_frame_is_writable(frame)) { | 1111 | ret = ff_inlink_make_frame_writable(link, &frame); |
| 1112 | av_log(link->dst, AV_LOG_DEBUG, "Copying data in avfilter.\n"); | ||
| 1113 | |||
| 1114 | switch (link->type) { | ||
| 1115 | case AVMEDIA_TYPE_VIDEO: | ||
| 1116 | out = ff_get_video_buffer(link, link->w, link->h); | ||
| 1117 | break; | ||
| 1118 | case AVMEDIA_TYPE_AUDIO: | ||
| 1119 | out = ff_get_audio_buffer(link, frame->nb_samples); | ||
| 1120 | break; | ||
| 1121 | default: | ||
| 1122 | ret = AVERROR(EINVAL); | ||
| 1123 | goto fail; | ||
| 1124 | } | ||
| 1125 | if (!out) { | ||
| 1126 | ret = AVERROR(ENOMEM); | ||
| 1127 | goto fail; | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | ret = av_frame_copy_props(out, frame); | ||
| 1131 | if (ret < 0) | 1112 | if (ret < 0) |
| 1132 | goto fail; | 1113 | goto fail; |
| 1133 | 1114 | } | |
| 1134 | switch (link->type) { | 1115 | out = frame; /* TODO rename */ |
| 1135 | case AVMEDIA_TYPE_VIDEO: | ||
| 1136 | av_image_copy(out->data, out->linesize, (const uint8_t **)frame->data, frame->linesize, | ||
| 1137 | frame->format, frame->width, frame->height); | ||
| 1138 | break; | ||
| 1139 | case AVMEDIA_TYPE_AUDIO: | ||
| 1140 | av_samples_copy(out->extended_data, frame->extended_data, | ||
| 1141 | 0, 0, frame->nb_samples, | ||
| 1142 | av_frame_get_channels(frame), | ||
| 1143 | frame->format); | ||
| 1144 | break; | ||
| 1145 | default: | ||
| 1146 | ret = AVERROR(EINVAL); | ||
| 1147 | goto fail; | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | av_frame_free(&frame); | ||
| 1151 | } else | ||
| 1152 | out = frame; | ||
| 1153 | 1116 | ||
| 1154 | while(cmd && cmd->time <= out->pts * av_q2d(link->time_base)){ | 1117 | while(cmd && cmd->time <= out->pts * av_q2d(link->time_base)){ |
| 1155 | av_log(link->dst, AV_LOG_DEBUG, | 1118 | av_log(link->dst, AV_LOG_DEBUG, |
| @@ -1559,6 +1522,55 @@ int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts · 403 unmodified lines | |||
| 1559 | return 1; | 1522 | return 1; |
| 1560 | } | 1523 | } |
| 1561 | 1524 | ||
| 1525 | int ff_inlink_make_frame_writable(AVFilterLink *link, AVFrame **rframe) | ||
| 1526 | { | ||
| 1527 | AVFrame *frame = *rframe; | ||
| 1528 | AVFrame *out; | ||
| 1529 | int ret; | ||
| 1530 | |||
| 1531 | if (av_frame_is_writable(frame)) | ||
| 1532 | return 0; | ||
| 1533 | av_log(link->dst, AV_LOG_DEBUG, "Copying data in avfilter.\n"); | ||
| 1534 | |||
| 1535 | switch (link->type) { | ||
| 1536 | case AVMEDIA_TYPE_VIDEO: | ||
| 1537 | out = ff_get_video_buffer(link, link->w, link->h); | ||
| 1538 | break; | ||
| 1539 | case AVMEDIA_TYPE_AUDIO: | ||
| 1540 | out = ff_get_audio_buffer(link, frame->nb_samples); | ||
| 1541 | break; | ||
| 1542 | default: | ||
| 1543 | return AVERROR(EINVAL); | ||
| 1544 | } | ||
| 1545 | if (!out) | ||
| 1546 | return AVERROR(ENOMEM); | ||
| 1547 | |||
| 1548 | ret = av_frame_copy_props(out, frame); | ||
| 1549 | if (ret < 0) { | ||
| 1550 | av_frame_free(&out); | ||
| 1551 | return ret; | ||
| 1552 | } | ||
| 1553 | |||
| 1554 | switch (link->type) { | ||
| 1555 | case AVMEDIA_TYPE_VIDEO: | ||
| 1556 | av_image_copy(out->data, out->linesize, (const uint8_t **)frame->data, frame->linesize, | ||
| 1557 | frame->format, frame->width, frame->height); | ||
| 1558 | break; | ||
| 1559 | case AVMEDIA_TYPE_AUDIO: | ||
| 1560 | av_samples_copy(out->extended_data, frame->extended_data, | ||
| 1561 | 0, 0, frame->nb_samples, | ||
| 1562 | av_frame_get_channels(frame), | ||
| 1563 | frame->format); | ||
| 1564 | break; | ||
| 1565 | default: | ||
| 1566 | av_assert0(!"reached"); | ||
| 1567 | } | ||
| 1568 | |||
| 1569 | av_frame_free(&frame); | ||
| 1570 | *rframe = out; | ||
| 1571 | return 0; | ||
| 1572 | } | ||
| 1573 | |||
| 1562 | const AVClass *avfilter_get_class(void) | 1574 | const AVClass *avfilter_get_class(void) |
| 1563 | { | 1575 | { |
| 1564 | return &avfilter_class; | 1576 | return &avfilter_class; |
| @@ -39,6 +39,13 @@ · 38 unmodified lines | |||
| 39 | */ | 39 | */ |
| 40 | void ff_filter_set_ready(AVFilterContext *filter, unsigned priority); | 40 | void ff_filter_set_ready(AVFilterContext *filter, unsigned priority); |
| 41 | 41 | ||
| 42 | /** | ||
| 43 | * Make sure a frame is writable. | ||
| 44 | * This is similar to av_frame_make_writable() except it uses the link's | ||
| 45 | * buffer allocation callback, and therefore allows direct rendering. | ||
| 46 | */ | ||
| 47 | int ff_inlink_make_frame_writable(AVFilterLink *link, AVFrame **rframe); | ||
| 48 | |||
| 42 | /** | 49 | /** |
| 43 | * Test and acknowledge the change of status on the link. | 50 | * Test and acknowledge the change of status on the link. |
| 44 | * | 51 | * |