Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2011 Stefano Sabatini
  3.  *
  4.  * This file is part of FFmpeg.
  5.  *
  6.  * FFmpeg is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * FFmpeg is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with FFmpeg; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19.  */
  20.  
  21. /**
  22.  * @file
  23.  * libavfilter virtual input device
  24.  */
  25.  
  26. /* #define DEBUG */
  27.  
  28. #include <float.h>              /* DBL_MIN, DBL_MAX */
  29.  
  30. #include "libavutil/bprint.h"
  31. #include "libavutil/channel_layout.h"
  32. #include "libavutil/file.h"
  33. #include "libavutil/internal.h"
  34. #include "libavutil/log.h"
  35. #include "libavutil/mem.h"
  36. #include "libavutil/opt.h"
  37. #include "libavutil/parseutils.h"
  38. #include "libavutil/pixdesc.h"
  39. #include "libavfilter/avfilter.h"
  40. #include "libavfilter/avfiltergraph.h"
  41. #include "libavfilter/buffersink.h"
  42. #include "libavformat/internal.h"
  43. #include "avdevice.h"
  44.  
  45. typedef struct {
  46.     AVClass *class;          ///< class for private options
  47.     char          *graph_str;
  48.     char          *graph_filename;
  49.     char          *dump_graph;
  50.     AVFilterGraph *graph;
  51.     AVFilterContext **sinks;
  52.     int *sink_stream_map;
  53.     int *sink_eof;
  54.     int *stream_sink_map;
  55.     int *sink_stream_subcc_map;
  56.     AVFrame *decoded_frame;
  57.     int nb_sinks;
  58.     AVPacket subcc_packet;
  59. } LavfiContext;
  60.  
  61. static int *create_all_formats(int n)
  62. {
  63.     int i, j, *fmts, count = 0;
  64.  
  65.     for (i = 0; i < n; i++) {
  66.         const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(i);
  67.         if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
  68.             count++;
  69.     }
  70.  
  71.     if (!(fmts = av_malloc((count+1) * sizeof(int))))
  72.         return NULL;
  73.     for (j = 0, i = 0; i < n; i++) {
  74.         const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(i);
  75.         if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
  76.             fmts[j++] = i;
  77.     }
  78.     fmts[j] = -1;
  79.     return fmts;
  80. }
  81.  
  82. av_cold static int lavfi_read_close(AVFormatContext *avctx)
  83. {
  84.     LavfiContext *lavfi = avctx->priv_data;
  85.  
  86.     av_freep(&lavfi->sink_stream_map);
  87.     av_freep(&lavfi->sink_eof);
  88.     av_freep(&lavfi->stream_sink_map);
  89.     av_freep(&lavfi->sink_stream_subcc_map);
  90.     av_freep(&lavfi->sinks);
  91.     avfilter_graph_free(&lavfi->graph);
  92.     av_frame_free(&lavfi->decoded_frame);
  93.  
  94.     return 0;
  95. }
  96.  
  97. static int create_subcc_streams(AVFormatContext *avctx)
  98. {
  99.     LavfiContext *lavfi = avctx->priv_data;
  100.     AVStream *st;
  101.     int stream_idx, sink_idx;
  102.  
  103.     for (stream_idx = 0; stream_idx < lavfi->nb_sinks; stream_idx++) {
  104.         sink_idx = lavfi->stream_sink_map[stream_idx];
  105.         if (lavfi->sink_stream_subcc_map[sink_idx]) {
  106.             lavfi->sink_stream_subcc_map[sink_idx] = avctx->nb_streams;
  107.             if (!(st = avformat_new_stream(avctx, NULL)))
  108.                 return AVERROR(ENOMEM);
  109.             st->codec->codec_id = AV_CODEC_ID_EIA_608;
  110.             st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
  111.         } else {
  112.             lavfi->sink_stream_subcc_map[sink_idx] = -1;
  113.         }
  114.     }
  115.     return 0;
  116. }
  117.  
  118. av_cold static int lavfi_read_header(AVFormatContext *avctx)
  119. {
  120.     LavfiContext *lavfi = avctx->priv_data;
  121.     AVFilterInOut *input_links = NULL, *output_links = NULL, *inout;
  122.     AVFilter *buffersink, *abuffersink;
  123.     int *pix_fmts = create_all_formats(AV_PIX_FMT_NB);
  124.     enum AVMediaType type;
  125.     int ret = 0, i, n;
  126.  
  127. #define FAIL(ERR) { ret = ERR; goto end; }
  128.  
  129.     if (!pix_fmts)
  130.         FAIL(AVERROR(ENOMEM));
  131.  
  132.     avfilter_register_all();
  133.  
  134.     buffersink = avfilter_get_by_name("buffersink");
  135.     abuffersink = avfilter_get_by_name("abuffersink");
  136.  
  137.     if (lavfi->graph_filename && lavfi->graph_str) {
  138.         av_log(avctx, AV_LOG_ERROR,
  139.                "Only one of the graph or graph_file options must be specified\n");
  140.         FAIL(AVERROR(EINVAL));
  141.     }
  142.  
  143.     if (lavfi->graph_filename) {
  144.         AVBPrint graph_file_pb;
  145.         AVIOContext *avio = NULL;
  146.         ret = avio_open(&avio, lavfi->graph_filename, AVIO_FLAG_READ);
  147.         if (ret < 0)
  148.             goto end;
  149.         av_bprint_init(&graph_file_pb, 0, AV_BPRINT_SIZE_UNLIMITED);
  150.         ret = avio_read_to_bprint(avio, &graph_file_pb, INT_MAX);
  151.         avio_closep(&avio);
  152.         av_bprint_chars(&graph_file_pb, '\0', 1);
  153.         if (!ret && !av_bprint_is_complete(&graph_file_pb))
  154.             ret = AVERROR(ENOMEM);
  155.         if (ret) {
  156.             av_bprint_finalize(&graph_file_pb, NULL);
  157.             goto end;
  158.         }
  159.         if ((ret = av_bprint_finalize(&graph_file_pb, &lavfi->graph_str)))
  160.             goto end;
  161.     }
  162.  
  163.     if (!lavfi->graph_str)
  164.         lavfi->graph_str = av_strdup(avctx->filename);
  165.  
  166.     /* parse the graph, create a stream for each open output */
  167.     if (!(lavfi->graph = avfilter_graph_alloc()))
  168.         FAIL(AVERROR(ENOMEM));
  169.  
  170.     if ((ret = avfilter_graph_parse_ptr(lavfi->graph, lavfi->graph_str,
  171.                                     &input_links, &output_links, avctx)) < 0)
  172.         goto end;
  173.  
  174.     if (input_links) {
  175.         av_log(avctx, AV_LOG_ERROR,
  176.                "Open inputs in the filtergraph are not acceptable\n");
  177.         FAIL(AVERROR(EINVAL));
  178.     }
  179.  
  180.     /* count the outputs */
  181.     for (n = 0, inout = output_links; inout; n++, inout = inout->next);
  182.     lavfi->nb_sinks = n;
  183.  
  184.     if (!(lavfi->sink_stream_map = av_malloc(sizeof(int) * n)))
  185.         FAIL(AVERROR(ENOMEM));
  186.     if (!(lavfi->sink_eof = av_mallocz(sizeof(int) * n)))
  187.         FAIL(AVERROR(ENOMEM));
  188.     if (!(lavfi->stream_sink_map = av_malloc(sizeof(int) * n)))
  189.         FAIL(AVERROR(ENOMEM));
  190.     if (!(lavfi->sink_stream_subcc_map = av_malloc(sizeof(int) * n)))
  191.         FAIL(AVERROR(ENOMEM));
  192.  
  193.     for (i = 0; i < n; i++)
  194.         lavfi->stream_sink_map[i] = -1;
  195.  
  196.     /* parse the output link names - they need to be of the form out0, out1, ...
  197.      * create a mapping between them and the streams */
  198.     for (i = 0, inout = output_links; inout; i++, inout = inout->next) {
  199.         int stream_idx = 0, suffix = 0, use_subcc = 0;
  200.         sscanf(inout->name, "out%n%d%n", &suffix, &stream_idx, &suffix);
  201.         if (!suffix) {
  202.             av_log(avctx,  AV_LOG_ERROR,
  203.                    "Invalid outpad name '%s'\n", inout->name);
  204.             FAIL(AVERROR(EINVAL));
  205.         }
  206.         if (inout->name[suffix]) {
  207.             if (!strcmp(inout->name + suffix, "+subcc")) {
  208.                 use_subcc = 1;
  209.             } else {
  210.                 av_log(avctx,  AV_LOG_ERROR,
  211.                        "Invalid outpad suffix '%s'\n", inout->name);
  212.                 FAIL(AVERROR(EINVAL));
  213.             }
  214.         }
  215.  
  216.         if ((unsigned)stream_idx >= n) {
  217.             av_log(avctx, AV_LOG_ERROR,
  218.                    "Invalid index was specified in output '%s', "
  219.                    "must be a non-negative value < %d\n",
  220.                    inout->name, n);
  221.             FAIL(AVERROR(EINVAL));
  222.         }
  223.  
  224.         if (lavfi->stream_sink_map[stream_idx] != -1) {
  225.             av_log(avctx,  AV_LOG_ERROR,
  226.                    "An output with stream index %d was already specified\n",
  227.                    stream_idx);
  228.             FAIL(AVERROR(EINVAL));
  229.         }
  230.         lavfi->sink_stream_map[i] = stream_idx;
  231.         lavfi->stream_sink_map[stream_idx] = i;
  232.         lavfi->sink_stream_subcc_map[i] = !!use_subcc;
  233.     }
  234.  
  235.     /* for each open output create a corresponding stream */
  236.     for (i = 0, inout = output_links; inout; i++, inout = inout->next) {
  237.         AVStream *st;
  238.         if (!(st = avformat_new_stream(avctx, NULL)))
  239.             FAIL(AVERROR(ENOMEM));
  240.         st->id = i;
  241.     }
  242.  
  243.     /* create a sink for each output and connect them to the graph */
  244.     lavfi->sinks = av_malloc_array(lavfi->nb_sinks, sizeof(AVFilterContext *));
  245.     if (!lavfi->sinks)
  246.         FAIL(AVERROR(ENOMEM));
  247.  
  248.     for (i = 0, inout = output_links; inout; i++, inout = inout->next) {
  249.         AVFilterContext *sink;
  250.  
  251.         type = avfilter_pad_get_type(inout->filter_ctx->output_pads, inout->pad_idx);
  252.  
  253.         if (type == AVMEDIA_TYPE_VIDEO && ! buffersink ||
  254.             type == AVMEDIA_TYPE_AUDIO && ! abuffersink) {
  255.                 av_log(avctx, AV_LOG_ERROR, "Missing required buffersink filter, aborting.\n");
  256.                 FAIL(AVERROR_FILTER_NOT_FOUND);
  257.         }
  258.  
  259.         if (type == AVMEDIA_TYPE_VIDEO) {
  260.             ret = avfilter_graph_create_filter(&sink, buffersink,
  261.                                                inout->name, NULL,
  262.                                                NULL, lavfi->graph);
  263.             if (ret >= 0)
  264.                 ret = av_opt_set_int_list(sink, "pix_fmts", pix_fmts,  AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
  265.             if (ret < 0)
  266.                 goto end;
  267.         } else if (type == AVMEDIA_TYPE_AUDIO) {
  268.             enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_U8,
  269.                                                   AV_SAMPLE_FMT_S16,
  270.                                                   AV_SAMPLE_FMT_S32,
  271.                                                   AV_SAMPLE_FMT_FLT,
  272.                                                   AV_SAMPLE_FMT_DBL, -1 };
  273.  
  274.             ret = avfilter_graph_create_filter(&sink, abuffersink,
  275.                                                inout->name, NULL,
  276.                                                NULL, lavfi->graph);
  277.             if (ret >= 0)
  278.                 ret = av_opt_set_int_list(sink, "sample_fmts", sample_fmts,  AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
  279.             if (ret < 0)
  280.                 goto end;
  281.             ret = av_opt_set_int(sink, "all_channel_counts", 1,
  282.                                  AV_OPT_SEARCH_CHILDREN);
  283.             if (ret < 0)
  284.                 goto end;
  285.         } else {
  286.             av_log(avctx,  AV_LOG_ERROR,
  287.                    "Output '%s' is not a video or audio output, not yet supported\n", inout->name);
  288.             FAIL(AVERROR(EINVAL));
  289.         }
  290.  
  291.         lavfi->sinks[i] = sink;
  292.         if ((ret = avfilter_link(inout->filter_ctx, inout->pad_idx, sink, 0)) < 0)
  293.             goto end;
  294.     }
  295.  
  296.     /* configure the graph */
  297.     if ((ret = avfilter_graph_config(lavfi->graph, avctx)) < 0)
  298.         goto end;
  299.  
  300.     if (lavfi->dump_graph) {
  301.         char *dump = avfilter_graph_dump(lavfi->graph, lavfi->dump_graph);
  302.         fputs(dump, stderr);
  303.         fflush(stderr);
  304.         av_free(dump);
  305.     }
  306.  
  307.     /* fill each stream with the information in the corresponding sink */
  308.     for (i = 0; i < lavfi->nb_sinks; i++) {
  309.         AVFilterLink *link = lavfi->sinks[lavfi->stream_sink_map[i]]->inputs[0];
  310.         AVStream *st = avctx->streams[i];
  311.         st->codec->codec_type = link->type;
  312.         avpriv_set_pts_info(st, 64, link->time_base.num, link->time_base.den);
  313.         if (link->type == AVMEDIA_TYPE_VIDEO) {
  314.             st->codec->codec_id   = AV_CODEC_ID_RAWVIDEO;
  315.             st->codec->pix_fmt    = link->format;
  316.             st->codec->time_base  = link->time_base;
  317.             st->codec->width      = link->w;
  318.             st->codec->height     = link->h;
  319.             st       ->sample_aspect_ratio =
  320.             st->codec->sample_aspect_ratio = link->sample_aspect_ratio;
  321.             avctx->probesize = FFMAX(avctx->probesize,
  322.                                      link->w * link->h *
  323.                                      av_get_padded_bits_per_pixel(av_pix_fmt_desc_get(link->format)) *
  324.                                      30);
  325.         } else if (link->type == AVMEDIA_TYPE_AUDIO) {
  326.             st->codec->codec_id    = av_get_pcm_codec(link->format, -1);
  327.             st->codec->channels    = avfilter_link_get_channels(link);
  328.             st->codec->sample_fmt  = link->format;
  329.             st->codec->sample_rate = link->sample_rate;
  330.             st->codec->time_base   = link->time_base;
  331.             st->codec->channel_layout = link->channel_layout;
  332.             if (st->codec->codec_id == AV_CODEC_ID_NONE)
  333.                 av_log(avctx, AV_LOG_ERROR,
  334.                        "Could not find PCM codec for sample format %s.\n",
  335.                        av_get_sample_fmt_name(link->format));
  336.         }
  337.     }
  338.  
  339.     if ((ret = create_subcc_streams(avctx)) < 0)
  340.         goto end;
  341.  
  342.     if (!(lavfi->decoded_frame = av_frame_alloc()))
  343.         FAIL(AVERROR(ENOMEM));
  344.  
  345. end:
  346.     av_free(pix_fmts);
  347.     avfilter_inout_free(&input_links);
  348.     avfilter_inout_free(&output_links);
  349.     if (ret < 0)
  350.         lavfi_read_close(avctx);
  351.     return ret;
  352. }
  353.  
  354. static int create_subcc_packet(AVFormatContext *avctx, AVFrame *frame,
  355.                                int sink_idx)
  356. {
  357.     LavfiContext *lavfi = avctx->priv_data;
  358.     AVFrameSideData *sd;
  359.     int stream_idx, i, ret;
  360.  
  361.     if ((stream_idx = lavfi->sink_stream_subcc_map[sink_idx]) < 0)
  362.         return 0;
  363.     for (i = 0; i < frame->nb_side_data; i++)
  364.         if (frame->side_data[i]->type == AV_FRAME_DATA_A53_CC)
  365.             break;
  366.     if (i >= frame->nb_side_data)
  367.         return 0;
  368.     sd = frame->side_data[i];
  369.     if ((ret = av_new_packet(&lavfi->subcc_packet, sd->size)) < 0)
  370.         return ret;
  371.     memcpy(lavfi->subcc_packet.data, sd->data, sd->size);
  372.     lavfi->subcc_packet.stream_index = stream_idx;
  373.     lavfi->subcc_packet.pts = frame->pts;
  374.     lavfi->subcc_packet.pos = av_frame_get_pkt_pos(frame);
  375.     return 0;
  376. }
  377.  
  378. static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
  379. {
  380.     LavfiContext *lavfi = avctx->priv_data;
  381.     double min_pts = DBL_MAX;
  382.     int stream_idx, min_pts_sink_idx = 0;
  383.     AVFrame *frame = lavfi->decoded_frame;
  384.     AVPicture pict;
  385.     AVDictionary *frame_metadata;
  386.     int ret, i;
  387.     int size = 0;
  388.  
  389.     if (lavfi->subcc_packet.size) {
  390.         *pkt = lavfi->subcc_packet;
  391.         av_init_packet(&lavfi->subcc_packet);
  392.         lavfi->subcc_packet.size = 0;
  393.         lavfi->subcc_packet.data = NULL;
  394.         return pkt->size;
  395.     }
  396.  
  397.     /* iterate through all the graph sinks. Select the sink with the
  398.      * minimum PTS */
  399.     for (i = 0; i < lavfi->nb_sinks; i++) {
  400.         AVRational tb = lavfi->sinks[i]->inputs[0]->time_base;
  401.         double d;
  402.         int ret;
  403.  
  404.         if (lavfi->sink_eof[i])
  405.             continue;
  406.  
  407.         ret = av_buffersink_get_frame_flags(lavfi->sinks[i], frame,
  408.                                             AV_BUFFERSINK_FLAG_PEEK);
  409.         if (ret == AVERROR_EOF) {
  410.             ff_dlog(avctx, "EOF sink_idx:%d\n", i);
  411.             lavfi->sink_eof[i] = 1;
  412.             continue;
  413.         } else if (ret < 0)
  414.             return ret;
  415.         d = av_rescale_q_rnd(frame->pts, tb, AV_TIME_BASE_Q, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
  416.         ff_dlog(avctx, "sink_idx:%d time:%f\n", i, d);
  417.         av_frame_unref(frame);
  418.  
  419.         if (d < min_pts) {
  420.             min_pts = d;
  421.             min_pts_sink_idx = i;
  422.         }
  423.     }
  424.     if (min_pts == DBL_MAX)
  425.         return AVERROR_EOF;
  426.  
  427.     ff_dlog(avctx, "min_pts_sink_idx:%i\n", min_pts_sink_idx);
  428.  
  429.     av_buffersink_get_frame_flags(lavfi->sinks[min_pts_sink_idx], frame, 0);
  430.     stream_idx = lavfi->sink_stream_map[min_pts_sink_idx];
  431.  
  432.     if (frame->width /* FIXME best way of testing a video */) {
  433.         size = avpicture_get_size(frame->format, frame->width, frame->height);
  434.         if ((ret = av_new_packet(pkt, size)) < 0)
  435.             return ret;
  436.  
  437.         memcpy(pict.data,     frame->data,     4*sizeof(frame->data[0]));
  438.         memcpy(pict.linesize, frame->linesize, 4*sizeof(frame->linesize[0]));
  439.  
  440.         avpicture_layout(&pict, frame->format, frame->width, frame->height,
  441.                          pkt->data, size);
  442.     } else if (av_frame_get_channels(frame) /* FIXME test audio */) {
  443.         size = frame->nb_samples * av_get_bytes_per_sample(frame->format) *
  444.                                    av_frame_get_channels(frame);
  445.         if ((ret = av_new_packet(pkt, size)) < 0)
  446.             return ret;
  447.         memcpy(pkt->data, frame->data[0], size);
  448.     }
  449.  
  450.     frame_metadata = av_frame_get_metadata(frame);
  451.     if (frame_metadata) {
  452.         uint8_t *metadata;
  453.         AVDictionaryEntry *e = NULL;
  454.         AVBPrint meta_buf;
  455.  
  456.         av_bprint_init(&meta_buf, 0, AV_BPRINT_SIZE_UNLIMITED);
  457.         while ((e = av_dict_get(frame_metadata, "", e, AV_DICT_IGNORE_SUFFIX))) {
  458.             av_bprintf(&meta_buf, "%s", e->key);
  459.             av_bprint_chars(&meta_buf, '\0', 1);
  460.             av_bprintf(&meta_buf, "%s", e->value);
  461.             av_bprint_chars(&meta_buf, '\0', 1);
  462.         }
  463.         if (!av_bprint_is_complete(&meta_buf) ||
  464.             !(metadata = av_packet_new_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA,
  465.                                                  meta_buf.len))) {
  466.             av_bprint_finalize(&meta_buf, NULL);
  467.             return AVERROR(ENOMEM);
  468.         }
  469.         memcpy(metadata, meta_buf.str, meta_buf.len);
  470.         av_bprint_finalize(&meta_buf, NULL);
  471.     }
  472.  
  473.     if ((ret = create_subcc_packet(avctx, frame, min_pts_sink_idx)) < 0) {
  474.         av_frame_unref(frame);
  475.         av_packet_unref(pkt);
  476.         return ret;
  477.     }
  478.  
  479.     pkt->stream_index = stream_idx;
  480.     pkt->pts = frame->pts;
  481.     pkt->pos = av_frame_get_pkt_pos(frame);
  482.     pkt->size = size;
  483.     av_frame_unref(frame);
  484.     return size;
  485. }
  486.  
  487. #define OFFSET(x) offsetof(LavfiContext, x)
  488.  
  489. #define DEC AV_OPT_FLAG_DECODING_PARAM
  490.  
  491. static const AVOption options[] = {
  492.     { "graph",     "set libavfilter graph", OFFSET(graph_str),  AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
  493.     { "graph_file","set libavfilter graph filename", OFFSET(graph_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC},
  494.     { "dumpgraph", "dump graph to stderr",  OFFSET(dump_graph), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
  495.     { NULL },
  496. };
  497.  
  498. static const AVClass lavfi_class = {
  499.     .class_name = "lavfi indev",
  500.     .item_name  = av_default_item_name,
  501.     .option     = options,
  502.     .version    = LIBAVUTIL_VERSION_INT,
  503.     .category   = AV_CLASS_CATEGORY_DEVICE_INPUT,
  504. };
  505.  
  506. AVInputFormat ff_lavfi_demuxer = {
  507.     .name           = "lavfi",
  508.     .long_name      = NULL_IF_CONFIG_SMALL("Libavfilter virtual input device"),
  509.     .priv_data_size = sizeof(LavfiContext),
  510.     .read_header    = lavfi_read_header,
  511.     .read_packet    = lavfi_read_packet,
  512.     .read_close     = lavfi_read_close,
  513.     .flags          = AVFMT_NOFILE,
  514.     .priv_class     = &lavfi_class,
  515. };
  516.