[{"id":1237,"web_url":"https://patchwork.libcamera.org/comment/1237/","msgid":"<40503fef-72d9-3ef9-54fa-af0e7049770a@ideasonboard.com>","date":"2019-04-03T04:24:27","subject":"Re: [libcamera-devel] [PATCH v2 3/4] cam: Extend request completion\n\thandler to deal with multiple streams","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Niklas,\n\nOn 03/04/2019 02:12, Niklas Söderlund wrote:\n> The completion handler needs to handle all buffers in the request. Solve\n> this by iterating over all buffers in the completed request and assign\n> each stream a name as we encounter them. The buffer writer needs to be\n> extended to learn about stream names so it can prefix the files it\n> writes with it.\n> \n> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> ---\n>  src/cam/buffer_writer.cpp |  5 +++--\n>  src/cam/buffer_writer.h   |  2 +-\n>  src/cam/main.cpp          | 42 ++++++++++++++++++++++++++++-----------\n>  3 files changed, 34 insertions(+), 15 deletions(-)\n> \n> diff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp\n> index 2d2258b4cd1cbbc2..b82ffaded688226a 100644\n> --- a/src/cam/buffer_writer.cpp\n> +++ b/src/cam/buffer_writer.cpp\n> @@ -19,13 +19,14 @@ BufferWriter::BufferWriter(const std::string &pattern)\n>  {\n>  }\n>  \n> -int BufferWriter::write(libcamera::Buffer *buffer)\n> +int BufferWriter::write(libcamera::Buffer *buffer,\n> +\t\t\tconst std::string &streamName)\n>  {\n>  \tstd::string filename;\n>  \tsize_t pos;\n>  \tint fd, ret = 0;\n>  \n> -\tfilename = pattern_;\n> +\tfilename = streamName + \"-\" + pattern_;\n>  \tpos = filename.find_first_of('#');\n>  \tif (pos != std::string::npos) {\n>  \t\tstd::stringstream ss;\n> diff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h\n> index 9705773e0e397d45..7bf785d1e83235ff 100644\n> --- a/src/cam/buffer_writer.h\n> +++ b/src/cam/buffer_writer.h\n> @@ -16,7 +16,7 @@ class BufferWriter\n>  public:\n>  \tBufferWriter(const std::string &pattern = \"frame-#.bin\");\n>  \n> -\tint write(libcamera::Buffer *buffer);\n> +\tint write(libcamera::Buffer *buffer, const std::string &streamName);\n>  \n>  private:\n>  \tstd::string pattern_;\n> diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> index b47bda21cbb7f220..9af7907a3d937c28 100644\n> --- a/src/cam/main.cpp\n> +++ b/src/cam/main.cpp\n> @@ -145,28 +145,46 @@ static int prepareCameraConfig(std::map<Stream *, StreamConfiguration> *config)\n>  \treturn 0;\n>  }\n>  \n> +static std::string streamToName(const Stream *stream)\n> +{\n> +\tstatic std::map<const Stream *, std::string> names;\n> +\n> +\tif (names.find(stream) == names.end())\n> +\t\tnames[stream] = std::string(\"stream\") + std::to_string(names.size());\n> +\n> +\treturn names[stream];\n> +}\n> +\n>  static void requestComplete(Request *request, const std::map<Stream *, Buffer *> &buffers)\n>  {\n>  \tstatic uint64_t last = 0;\n> +\tdouble fps = 0.0;\n>  \n>  \tif (request->status() == Request::RequestCancelled)\n>  \t\treturn;\n>  \n> -\tBuffer *buffer = buffers.begin()->second;\n> +\tfor (auto it = buffers.begin(); it != buffers.end(); ++it) {\n> +\t\tStream *stream = it->first;\n> +\t\tBuffer *buffer = it->second;\n> +\t\tstd::string name = streamToName(stream);\n>  \n> -\tdouble fps = buffer->timestamp() - last;\n> -\tfps = last && fps ? 1000000000.0 / fps : 0.0;\n> -\tlast = buffer->timestamp();\n> +\t\tif (it == buffers.begin()) {\n> +\t\t\tfps = buffer->timestamp() - last;\n> +\t\t\tfps = last && fps ? 1000000000.0 / fps : 0.0;\n> +\t\t\tlast = buffer->timestamp();\n> +\t\t}\n\n\nShould we track FPS on a per stream basis? Here you are really\ncalculating Requests (with at least one buffer) per second, which might\nbe a perfectly reasonable thing to calculate, but what if (as a simple\nextreme) I queued up requests to alternate between two streams A and B.\n\n--------\nR:1 A\nR:2    B\nR:3 A\nR:4    B\n--------\n\nIs that 4 frames per interval? or two?\n\n\nIt might be worth splitting the calculation out to a function and\nstoring the result on a per stream basis without using static locals.\n\n>  \n> -\tstd::cout << \"seq: \" << std::setw(6) << std::setfill('0') << buffer->sequence()\n> -\t\t  << \" buf: \" << buffer->index()\n> -\t\t  << \" bytesused: \" << buffer->bytesused()\n> -\t\t  << \" timestamp: \" << buffer->timestamp()\n> -\t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n> -\t\t  << std::endl;\n> +\t\tstd::cout << name << \" seq: \" << std::setw(6)\n> +\t\t\t  << std::setfill('0') << buffer->sequence()\n> +\t\t\t  << \" buf: \" << buffer->index()\n> +\t\t\t  << \" bytesused: \" << buffer->bytesused()\n> +\t\t\t  << \" timestamp: \" << buffer->timestamp()\n> +\t\t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n> +\t\t\t  << std::endl;\n>  \n> -\tif (writer)\n> -\t\twriter->write(buffer);\n> +\t\tif (writer)\n> +\t\t\twriter->write(buffer, name);\n> +\t}\n>  \n>  \trequest = camera->createRequest();\n>  \tif (!request) {\n>","headers":{"Return-Path":"<kieran.bingham@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E7E50610B3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  3 Apr 2019 06:24:33 +0200 (CEST)","from [10.71.11.124] (unknown [147.50.13.10])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 26F5A2F9;\n\tWed,  3 Apr 2019 06:24:31 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1554265473;\n\tbh=KnFuKCRc5/zuazLRZ7efll2B1ao9beDg5b/LKUEJuo8=;\n\th=Reply-To:Subject:To:References:From:Date:In-Reply-To:From;\n\tb=bQQ89hFLWbFHBAFfzX+GmZFWCHYLB4XLOavdWjVy7NUSgJMVlX92evxvMtVdSxahr\n\tuJryoVqNnpFyuySAcMgIqtKj2tbNJUNVySjgjXBaTcJwfaodWAk2hk1V2vgSYxS7t2\n\tzxJghrZfPIAsctB/TRP9mGd+LJILBMtA81OPTEZM=","Reply-To":"kieran.bingham@ideasonboard.com","To":"=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20190403011235.12782-1-niklas.soderlund@ragnatech.se>\n\t<20190403011235.12782-4-niklas.soderlund@ragnatech.se>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Openpgp":"preference=signencrypt","Autocrypt":"addr=kieran.bingham@ideasonboard.com; keydata=\n\t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\n\tsbsRB8KNNvVXBOVNwko86rQqF9drZuw=","Organization":"Ideas on Board","Message-ID":"<40503fef-72d9-3ef9-54fa-af0e7049770a@ideasonboard.com>","Date":"Wed, 3 Apr 2019 11:24:27 +0700","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101\n\tThunderbird/60.5.1","MIME-Version":"1.0","In-Reply-To":"<20190403011235.12782-4-niklas.soderlund@ragnatech.se>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH v2 3/4] cam: Extend request completion\n\thandler to deal with multiple streams","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Wed, 03 Apr 2019 04:24:34 -0000"}},{"id":1243,"web_url":"https://patchwork.libcamera.org/comment/1243/","msgid":"<20190403070722.GF4813@pendragon.ideasonboard.com>","date":"2019-04-03T07:07:22","subject":"Re: [libcamera-devel] [PATCH v2 3/4] cam: Extend request completion\n\thandler to deal with multiple streams","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Kieran,\n\nOn Wed, Apr 03, 2019 at 11:24:27AM +0700, Kieran Bingham wrote:\n> On 03/04/2019 02:12, Niklas Söderlund wrote:\n> > The completion handler needs to handle all buffers in the request. Solve\n> > this by iterating over all buffers in the completed request and assign\n> > each stream a name as we encounter them. The buffer writer needs to be\n> > extended to learn about stream names so it can prefix the files it\n> > writes with it.\n> > \n> > Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> > ---\n> >  src/cam/buffer_writer.cpp |  5 +++--\n> >  src/cam/buffer_writer.h   |  2 +-\n> >  src/cam/main.cpp          | 42 ++++++++++++++++++++++++++++-----------\n> >  3 files changed, 34 insertions(+), 15 deletions(-)\n> > \n> > diff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp\n> > index 2d2258b4cd1cbbc2..b82ffaded688226a 100644\n> > --- a/src/cam/buffer_writer.cpp\n> > +++ b/src/cam/buffer_writer.cpp\n> > @@ -19,13 +19,14 @@ BufferWriter::BufferWriter(const std::string &pattern)\n> >  {\n> >  }\n> >  \n> > -int BufferWriter::write(libcamera::Buffer *buffer)\n> > +int BufferWriter::write(libcamera::Buffer *buffer,\n> > +\t\t\tconst std::string &streamName)\n> >  {\n> >  \tstd::string filename;\n> >  \tsize_t pos;\n> >  \tint fd, ret = 0;\n> >  \n> > -\tfilename = pattern_;\n> > +\tfilename = streamName + \"-\" + pattern_;\n> >  \tpos = filename.find_first_of('#');\n> >  \tif (pos != std::string::npos) {\n> >  \t\tstd::stringstream ss;\n> > diff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h\n> > index 9705773e0e397d45..7bf785d1e83235ff 100644\n> > --- a/src/cam/buffer_writer.h\n> > +++ b/src/cam/buffer_writer.h\n> > @@ -16,7 +16,7 @@ class BufferWriter\n> >  public:\n> >  \tBufferWriter(const std::string &pattern = \"frame-#.bin\");\n> >  \n> > -\tint write(libcamera::Buffer *buffer);\n> > +\tint write(libcamera::Buffer *buffer, const std::string &streamName);\n> >  \n> >  private:\n> >  \tstd::string pattern_;\n> > diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> > index b47bda21cbb7f220..9af7907a3d937c28 100644\n> > --- a/src/cam/main.cpp\n> > +++ b/src/cam/main.cpp\n> > @@ -145,28 +145,46 @@ static int prepareCameraConfig(std::map<Stream *, StreamConfiguration> *config)\n> >  \treturn 0;\n> >  }\n> >  \n> > +static std::string streamToName(const Stream *stream)\n> > +{\n> > +\tstatic std::map<const Stream *, std::string> names;\n> > +\n> > +\tif (names.find(stream) == names.end())\n> > +\t\tnames[stream] = std::string(\"stream\") + std::to_string(names.size());\n> > +\n> > +\treturn names[stream];\n> > +}\n> > +\n> >  static void requestComplete(Request *request, const std::map<Stream *, Buffer *> &buffers)\n> >  {\n> >  \tstatic uint64_t last = 0;\n> > +\tdouble fps = 0.0;\n> >  \n> >  \tif (request->status() == Request::RequestCancelled)\n> >  \t\treturn;\n> >  \n> > -\tBuffer *buffer = buffers.begin()->second;\n> > +\tfor (auto it = buffers.begin(); it != buffers.end(); ++it) {\n> > +\t\tStream *stream = it->first;\n> > +\t\tBuffer *buffer = it->second;\n> > +\t\tstd::string name = streamToName(stream);\n> >  \n> > -\tdouble fps = buffer->timestamp() - last;\n> > -\tfps = last && fps ? 1000000000.0 / fps : 0.0;\n> > -\tlast = buffer->timestamp();\n> > +\t\tif (it == buffers.begin()) {\n> > +\t\t\tfps = buffer->timestamp() - last;\n> > +\t\t\tfps = last && fps ? 1000000000.0 / fps : 0.0;\n> > +\t\t\tlast = buffer->timestamp();\n> > +\t\t}\n> \n> \n> Should we track FPS on a per stream basis? Here you are really\n> calculating Requests (with at least one buffer) per second, which might\n> be a perfectly reasonable thing to calculate, but what if (as a simple\n> extreme) I queued up requests to alternate between two streams A and B.\n> \n> --------\n> R:1 A\n> R:2    B\n> R:3 A\n> R:4    B\n> --------\n> \n> Is that 4 frames per interval? or two?\n\nI think the most interesting FPS value relates to the frame rate of the\nsensor, so that should be tracked at the request level, not the stream\nlevel. It could however make sense to count the number of frames\ncaptured for every stream and add the counts to the log message.\n\n> It might be worth splitting the calculation out to a function and\n> storing the result on a per stream basis without using static locals.\n\nWe should create a top-level class for the cam application to store the\nexisting global variables.\n\n> >  \n> > -\tstd::cout << \"seq: \" << std::setw(6) << std::setfill('0') << buffer->sequence()\n> > -\t\t  << \" buf: \" << buffer->index()\n> > -\t\t  << \" bytesused: \" << buffer->bytesused()\n> > -\t\t  << \" timestamp: \" << buffer->timestamp()\n> > -\t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n> > -\t\t  << std::endl;\n> > +\t\tstd::cout << name << \" seq: \" << std::setw(6)\n> > +\t\t\t  << std::setfill('0') << buffer->sequence()\n> > +\t\t\t  << \" buf: \" << buffer->index()\n> > +\t\t\t  << \" bytesused: \" << buffer->bytesused()\n> > +\t\t\t  << \" timestamp: \" << buffer->timestamp()\n> > +\t\t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n> > +\t\t\t  << std::endl;\n> >  \n> > -\tif (writer)\n> > -\t\twriter->write(buffer);\n> > +\t\tif (writer)\n> > +\t\t\twriter->write(buffer, name);\n> > +\t}\n> >  \n> >  \trequest = camera->createRequest();\n> >  \tif (!request) {","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id BDEDD60DB2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  3 Apr 2019 09:07:33 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 17F312F9;\n\tWed,  3 Apr 2019 09:07:33 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1554275253;\n\tbh=fh+076Nr4kva9LKlEPihlFp1MD/13ouvqk32bbQc4Kc=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=vnqI8pwb8aEYowKkd9K7SrdnquKaE9baoSqWExXvSuXjAcGAMHwaJDczAKYhyF9uf\n\tnT1gn2uVPM68V/RuAfGwtKhnQ0lf2/LYi1uRzZ6geCyitzqP4Xnq7MCgCUZsBmQZNz\n\tE4W++fQVJEZjeYZQxhsOsA4r+pRj8uw1r636SO0w=","Date":"Wed, 3 Apr 2019 10:07:22 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>,\n\tlibcamera-devel@lists.libcamera.org","Message-ID":"<20190403070722.GF4813@pendragon.ideasonboard.com>","References":"<20190403011235.12782-1-niklas.soderlund@ragnatech.se>\n\t<20190403011235.12782-4-niklas.soderlund@ragnatech.se>\n\t<40503fef-72d9-3ef9-54fa-af0e7049770a@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<40503fef-72d9-3ef9-54fa-af0e7049770a@ideasonboard.com>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v2 3/4] cam: Extend request completion\n\thandler to deal with multiple streams","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Wed, 03 Apr 2019 07:07:34 -0000"}},{"id":1257,"web_url":"https://patchwork.libcamera.org/comment/1257/","msgid":"<20190403140541.7sjpfcmude4r332p@uno.localdomain>","date":"2019-04-03T14:05:41","subject":"Re: [libcamera-devel] [PATCH v2 3/4] cam: Extend request completion\n\thandler to deal with multiple streams","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Niklas,\n\nOn Wed, Apr 03, 2019 at 03:12:34AM +0200, Niklas Söderlund wrote:\n> The completion handler needs to handle all buffers in the request. Solve\n> this by iterating over all buffers in the completed request and assign\n> each stream a name as we encounter them. The buffer writer needs to be\n> extended to learn about stream names so it can prefix the files it\n> writes with it.\n>\n> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> ---\n>  src/cam/buffer_writer.cpp |  5 +++--\n>  src/cam/buffer_writer.h   |  2 +-\n>  src/cam/main.cpp          | 42 ++++++++++++++++++++++++++++-----------\n>  3 files changed, 34 insertions(+), 15 deletions(-)\n>\n> diff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp\n> index 2d2258b4cd1cbbc2..b82ffaded688226a 100644\n> --- a/src/cam/buffer_writer.cpp\n> +++ b/src/cam/buffer_writer.cpp\n> @@ -19,13 +19,14 @@ BufferWriter::BufferWriter(const std::string &pattern)\n>  {\n>  }\n>\n> -int BufferWriter::write(libcamera::Buffer *buffer)\n> +int BufferWriter::write(libcamera::Buffer *buffer,\n> +\t\t\tconst std::string &streamName)\n>  {\n>  \tstd::string filename;\n>  \tsize_t pos;\n>  \tint fd, ret = 0;\n>\n> -\tfilename = pattern_;\n> +\tfilename = streamName + \"-\" + pattern_;\n>  \tpos = filename.find_first_of('#');\n>  \tif (pos != std::string::npos) {\n>  \t\tstd::stringstream ss;\n> diff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h\n> index 9705773e0e397d45..7bf785d1e83235ff 100644\n> --- a/src/cam/buffer_writer.h\n> +++ b/src/cam/buffer_writer.h\n> @@ -16,7 +16,7 @@ class BufferWriter\n>  public:\n>  \tBufferWriter(const std::string &pattern = \"frame-#.bin\");\n>\n> -\tint write(libcamera::Buffer *buffer);\n> +\tint write(libcamera::Buffer *buffer, const std::string &streamName);\n>\n>  private:\n>  \tstd::string pattern_;\n> diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> index b47bda21cbb7f220..9af7907a3d937c28 100644\n> --- a/src/cam/main.cpp\n> +++ b/src/cam/main.cpp\n> @@ -145,28 +145,46 @@ static int prepareCameraConfig(std::map<Stream *, StreamConfiguration> *config)\n>  \treturn 0;\n>  }\n>\n> +static std::string streamToName(const Stream *stream)\n> +{\n> +\tstatic std::map<const Stream *, std::string> names;\n> +\n> +\tif (names.find(stream) == names.end())\n> +\t\tnames[stream] = std::string(\"stream\") + std::to_string(names.size());\n> +\n> +\treturn names[stream];\n> +}\n> +\n>  static void requestComplete(Request *request, const std::map<Stream *, Buffer *> &buffers)\n>  {\n>  \tstatic uint64_t last = 0;\n> +\tdouble fps = 0.0;\n>\n>  \tif (request->status() == Request::RequestCancelled)\n>  \t\treturn;\n>\n> -\tBuffer *buffer = buffers.begin()->second;\n> +\tfor (auto it = buffers.begin(); it != buffers.end(); ++it) {\n> +\t\tStream *stream = it->first;\n> +\t\tBuffer *buffer = it->second;\n> +\t\tstd::string name = streamToName(stream);\n\nAs I've run into this issue before, and I solved it in a quite hackish\nway, how would you here deal with the following scenario:\n\n1) Create a request\n2) Add <Stream *viewfinder, Buffer *buffer> to the request\n3) int x = 0;\n4) Queue the request;\n5) Handle the completed request;\n6) Re-add the just completed <Stream *viewfinder, Buffer *buffer> pair\n7) if (x < 10) then x++; goto 4); else goto 8)\n8) Add a <Stream *stillcapture, Buffer *buffer> to the request\n9) Handle the completed request, now with 2 streams\n10) Requeue viewfinder only\n\nAll this procedure just to say: how would an application recognize\nwhat stream is for which usage? Should they keep track of that or do\nwe plan to provide a way to make Streams identifiable? (eg. by adding\nthe StreamUsage to the Stream)\n\nThanks\n  j\n\n>\n> -\tdouble fps = buffer->timestamp() - last;\n> -\tfps = last && fps ? 1000000000.0 / fps : 0.0;\n> -\tlast = buffer->timestamp();\n> +\t\tif (it == buffers.begin()) {\n> +\t\t\tfps = buffer->timestamp() - last;\n> +\t\t\tfps = last && fps ? 1000000000.0 / fps : 0.0;\n> +\t\t\tlast = buffer->timestamp();\n> +\t\t}\n>\n> -\tstd::cout << \"seq: \" << std::setw(6) << std::setfill('0') << buffer->sequence()\n> -\t\t  << \" buf: \" << buffer->index()\n> -\t\t  << \" bytesused: \" << buffer->bytesused()\n> -\t\t  << \" timestamp: \" << buffer->timestamp()\n> -\t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n> -\t\t  << std::endl;\n> +\t\tstd::cout << name << \" seq: \" << std::setw(6)\n> +\t\t\t  << std::setfill('0') << buffer->sequence()\n> +\t\t\t  << \" buf: \" << buffer->index()\n> +\t\t\t  << \" bytesused: \" << buffer->bytesused()\n> +\t\t\t  << \" timestamp: \" << buffer->timestamp()\n> +\t\t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n> +\t\t\t  << std::endl;\n>\n> -\tif (writer)\n> -\t\twriter->write(buffer);\n> +\t\tif (writer)\n> +\t\t\twriter->write(buffer, name);\n> +\t}\n>\n>  \trequest = camera->createRequest();\n>  \tif (!request) {\n> --\n> 2.21.0\n>\n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net\n\t[217.70.183.200])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 75C9A600FB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  3 Apr 2019 16:04:56 +0200 (CEST)","from uno.localdomain (2-224-242-101.ip172.fastwebnet.it\n\t[2.224.242.101]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay7-d.mail.gandi.net (Postfix) with ESMTPSA id 0154520005;\n\tWed,  3 Apr 2019 14:04:55 +0000 (UTC)"],"X-Originating-IP":"2.224.242.101","Date":"Wed, 3 Apr 2019 16:05:41 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190403140541.7sjpfcmude4r332p@uno.localdomain>","References":"<20190403011235.12782-1-niklas.soderlund@ragnatech.se>\n\t<20190403011235.12782-4-niklas.soderlund@ragnatech.se>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"5hmtbxcohqm5eq5t\"","Content-Disposition":"inline","In-Reply-To":"<20190403011235.12782-4-niklas.soderlund@ragnatech.se>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH v2 3/4] cam: Extend request completion\n\thandler to deal with multiple streams","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Wed, 03 Apr 2019 14:04:56 -0000"}},{"id":1258,"web_url":"https://patchwork.libcamera.org/comment/1258/","msgid":"<20190403144410.ctl3e45qav37wpk7@uno.localdomain>","date":"2019-04-03T14:44:10","subject":"Re: [libcamera-devel] [PATCH v2 3/4] cam: Extend request completion\n\thandler to deal with multiple streams","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Niklas,\n\nOn Wed, Apr 03, 2019 at 03:12:34AM +0200, Niklas Söderlund wrote:\n> The completion handler needs to handle all buffers in the request. Solve\n> this by iterating over all buffers in the completed request and assign\n> each stream a name as we encounter them. The buffer writer needs to be\n> extended to learn about stream names so it can prefix the files it\n> writes with it.\n>\n> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> ---\n>  src/cam/buffer_writer.cpp |  5 +++--\n>  src/cam/buffer_writer.h   |  2 +-\n>  src/cam/main.cpp          | 42 ++++++++++++++++++++++++++++-----------\n>  3 files changed, 34 insertions(+), 15 deletions(-)\n>\n> diff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp\n> index 2d2258b4cd1cbbc2..b82ffaded688226a 100644\n> --- a/src/cam/buffer_writer.cpp\n> +++ b/src/cam/buffer_writer.cpp\n> @@ -19,13 +19,14 @@ BufferWriter::BufferWriter(const std::string &pattern)\n>  {\n>  }\n>\n> -int BufferWriter::write(libcamera::Buffer *buffer)\n> +int BufferWriter::write(libcamera::Buffer *buffer,\n> +\t\t\tconst std::string &streamName)\n>  {\n>  \tstd::string filename;\n>  \tsize_t pos;\n>  \tint fd, ret = 0;\n>\n> -\tfilename = pattern_;\n> +\tfilename = streamName + \"-\" + pattern_;\n\nthis should be the other way around, otherwise I get:\nstream1-/tmp/frame-#\n\nFYI I sent this exact same patch in my v4 imgu+multi stream series:\n\"[PATCH v4 28/31] src: cam: Add output name to frame writer\"\nwhere I handle multiple stream requests too, as I assume you have not\nseen that series.\n\nthanks\n  j\n\n\n>  \tpos = filename.find_first_of('#');\n>  \tif (pos != std::string::npos) {\n>  \t\tstd::stringstream ss;\n> diff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h\n> index 9705773e0e397d45..7bf785d1e83235ff 100644\n> --- a/src/cam/buffer_writer.h\n> +++ b/src/cam/buffer_writer.h\n> @@ -16,7 +16,7 @@ class BufferWriter\n>  public:\n>  \tBufferWriter(const std::string &pattern = \"frame-#.bin\");\n>\n> -\tint write(libcamera::Buffer *buffer);\n> +\tint write(libcamera::Buffer *buffer, const std::string &streamName);\n>\n>  private:\n>  \tstd::string pattern_;\n> diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> index b47bda21cbb7f220..9af7907a3d937c28 100644\n> --- a/src/cam/main.cpp\n> +++ b/src/cam/main.cpp\n> @@ -145,28 +145,46 @@ static int prepareCameraConfig(std::map<Stream *, StreamConfiguration> *config)\n>  \treturn 0;\n>  }\n>\n> +static std::string streamToName(const Stream *stream)\n> +{\n> +\tstatic std::map<const Stream *, std::string> names;\n> +\n> +\tif (names.find(stream) == names.end())\n> +\t\tnames[stream] = std::string(\"stream\") + std::to_string(names.size());\n> +\n> +\treturn names[stream];\n> +}\n> +\n>  static void requestComplete(Request *request, const std::map<Stream *, Buffer *> &buffers)\n>  {\n>  \tstatic uint64_t last = 0;\n> +\tdouble fps = 0.0;\n>\n>  \tif (request->status() == Request::RequestCancelled)\n>  \t\treturn;\n>\n> -\tBuffer *buffer = buffers.begin()->second;\n> +\tfor (auto it = buffers.begin(); it != buffers.end(); ++it) {\n> +\t\tStream *stream = it->first;\n> +\t\tBuffer *buffer = it->second;\n> +\t\tstd::string name = streamToName(stream);\n>\n> -\tdouble fps = buffer->timestamp() - last;\n> -\tfps = last && fps ? 1000000000.0 / fps : 0.0;\n> -\tlast = buffer->timestamp();\n> +\t\tif (it == buffers.begin()) {\n> +\t\t\tfps = buffer->timestamp() - last;\n> +\t\t\tfps = last && fps ? 1000000000.0 / fps : 0.0;\n> +\t\t\tlast = buffer->timestamp();\n> +\t\t}\n>\n> -\tstd::cout << \"seq: \" << std::setw(6) << std::setfill('0') << buffer->sequence()\n> -\t\t  << \" buf: \" << buffer->index()\n> -\t\t  << \" bytesused: \" << buffer->bytesused()\n> -\t\t  << \" timestamp: \" << buffer->timestamp()\n> -\t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n> -\t\t  << std::endl;\n> +\t\tstd::cout << name << \" seq: \" << std::setw(6)\n> +\t\t\t  << std::setfill('0') << buffer->sequence()\n> +\t\t\t  << \" buf: \" << buffer->index()\n> +\t\t\t  << \" bytesused: \" << buffer->bytesused()\n> +\t\t\t  << \" timestamp: \" << buffer->timestamp()\n> +\t\t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n> +\t\t\t  << std::endl;\n>\n> -\tif (writer)\n> -\t\twriter->write(buffer);\n> +\t\tif (writer)\n> +\t\t\twriter->write(buffer, name);\n> +\t}\n>\n>  \trequest = camera->createRequest();\n>  \tif (!request) {\n> --\n> 2.21.0\n>\n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net\n\t[217.70.183.195])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B8DDE600FB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  3 Apr 2019 16:43:24 +0200 (CEST)","from uno.localdomain (2-224-242-101.ip172.fastwebnet.it\n\t[2.224.242.101]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 3BD4B60004;\n\tWed,  3 Apr 2019 14:43:24 +0000 (UTC)"],"X-Originating-IP":"2.224.242.101","Date":"Wed, 3 Apr 2019 16:44:10 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190403144410.ctl3e45qav37wpk7@uno.localdomain>","References":"<20190403011235.12782-1-niklas.soderlund@ragnatech.se>\n\t<20190403011235.12782-4-niklas.soderlund@ragnatech.se>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"qd22qhq2tvyvdgn6\"","Content-Disposition":"inline","In-Reply-To":"<20190403011235.12782-4-niklas.soderlund@ragnatech.se>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH v2 3/4] cam: Extend request completion\n\thandler to deal with multiple streams","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Wed, 03 Apr 2019 14:43:24 -0000"}},{"id":1264,"web_url":"https://patchwork.libcamera.org/comment/1264/","msgid":"<20190404000514.GM23466@bigcity.dyn.berto.se>","date":"2019-04-04T00:05:14","subject":"Re: [libcamera-devel] [PATCH v2 3/4] cam: Extend request completion\n\thandler to deal with multiple streams","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Jacopo,\n\nThanks for your feedback.\n\nOn 2019-04-03 16:05:41 +0200, Jacopo Mondi wrote:\n> Hi Niklas,\n> \n> On Wed, Apr 03, 2019 at 03:12:34AM +0200, Niklas Söderlund wrote:\n> > The completion handler needs to handle all buffers in the request. Solve\n> > this by iterating over all buffers in the completed request and assign\n> > each stream a name as we encounter them. The buffer writer needs to be\n> > extended to learn about stream names so it can prefix the files it\n> > writes with it.\n> >\n> > Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> > ---\n> >  src/cam/buffer_writer.cpp |  5 +++--\n> >  src/cam/buffer_writer.h   |  2 +-\n> >  src/cam/main.cpp          | 42 ++++++++++++++++++++++++++++-----------\n> >  3 files changed, 34 insertions(+), 15 deletions(-)\n> >\n> > diff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp\n> > index 2d2258b4cd1cbbc2..b82ffaded688226a 100644\n> > --- a/src/cam/buffer_writer.cpp\n> > +++ b/src/cam/buffer_writer.cpp\n> > @@ -19,13 +19,14 @@ BufferWriter::BufferWriter(const std::string &pattern)\n> >  {\n> >  }\n> >\n> > -int BufferWriter::write(libcamera::Buffer *buffer)\n> > +int BufferWriter::write(libcamera::Buffer *buffer,\n> > +\t\t\tconst std::string &streamName)\n> >  {\n> >  \tstd::string filename;\n> >  \tsize_t pos;\n> >  \tint fd, ret = 0;\n> >\n> > -\tfilename = pattern_;\n> > +\tfilename = streamName + \"-\" + pattern_;\n> >  \tpos = filename.find_first_of('#');\n> >  \tif (pos != std::string::npos) {\n> >  \t\tstd::stringstream ss;\n> > diff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h\n> > index 9705773e0e397d45..7bf785d1e83235ff 100644\n> > --- a/src/cam/buffer_writer.h\n> > +++ b/src/cam/buffer_writer.h\n> > @@ -16,7 +16,7 @@ class BufferWriter\n> >  public:\n> >  \tBufferWriter(const std::string &pattern = \"frame-#.bin\");\n> >\n> > -\tint write(libcamera::Buffer *buffer);\n> > +\tint write(libcamera::Buffer *buffer, const std::string &streamName);\n> >\n> >  private:\n> >  \tstd::string pattern_;\n> > diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> > index b47bda21cbb7f220..9af7907a3d937c28 100644\n> > --- a/src/cam/main.cpp\n> > +++ b/src/cam/main.cpp\n> > @@ -145,28 +145,46 @@ static int prepareCameraConfig(std::map<Stream *, StreamConfiguration> *config)\n> >  \treturn 0;\n> >  }\n> >\n> > +static std::string streamToName(const Stream *stream)\n> > +{\n> > +\tstatic std::map<const Stream *, std::string> names;\n> > +\n> > +\tif (names.find(stream) == names.end())\n> > +\t\tnames[stream] = std::string(\"stream\") + std::to_string(names.size());\n> > +\n> > +\treturn names[stream];\n> > +}\n> > +\n> >  static void requestComplete(Request *request, const std::map<Stream *, Buffer *> &buffers)\n> >  {\n> >  \tstatic uint64_t last = 0;\n> > +\tdouble fps = 0.0;\n> >\n> >  \tif (request->status() == Request::RequestCancelled)\n> >  \t\treturn;\n> >\n> > -\tBuffer *buffer = buffers.begin()->second;\n> > +\tfor (auto it = buffers.begin(); it != buffers.end(); ++it) {\n> > +\t\tStream *stream = it->first;\n> > +\t\tBuffer *buffer = it->second;\n> > +\t\tstd::string name = streamToName(stream);\n> \n> As I've run into this issue before, and I solved it in a quite hackish\n> way, how would you here deal with the following scenario:\n> \n> 1) Create a request\n> 2) Add <Stream *viewfinder, Buffer *buffer> to the request\n> 3) int x = 0;\n> 4) Queue the request;\n> 5) Handle the completed request;\n> 6) Re-add the just completed <Stream *viewfinder, Buffer *buffer> pair\n> 7) if (x < 10) then x++; goto 4); else goto 8)\n> 8) Add a <Stream *stillcapture, Buffer *buffer> to the request\n> 9) Handle the completed request, now with 2 streams\n> 10) Requeue viewfinder only\n> \n> All this procedure just to say: how would an application recognize\n> what stream is for which usage? Should they keep track of that or do\n> we plan to provide a way to make Streams identifiable? (eg. by adding\n> the StreamUsage to the Stream)\n\nThis is a good question and on outstanding issue we need to solve really \nsoon. Currently there is no way to make a stream identifiable.\n\n> \n> Thanks\n>   j\n> \n> >\n> > -\tdouble fps = buffer->timestamp() - last;\n> > -\tfps = last && fps ? 1000000000.0 / fps : 0.0;\n> > -\tlast = buffer->timestamp();\n> > +\t\tif (it == buffers.begin()) {\n> > +\t\t\tfps = buffer->timestamp() - last;\n> > +\t\t\tfps = last && fps ? 1000000000.0 / fps : 0.0;\n> > +\t\t\tlast = buffer->timestamp();\n> > +\t\t}\n> >\n> > -\tstd::cout << \"seq: \" << std::setw(6) << std::setfill('0') << buffer->sequence()\n> > -\t\t  << \" buf: \" << buffer->index()\n> > -\t\t  << \" bytesused: \" << buffer->bytesused()\n> > -\t\t  << \" timestamp: \" << buffer->timestamp()\n> > -\t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n> > -\t\t  << std::endl;\n> > +\t\tstd::cout << name << \" seq: \" << std::setw(6)\n> > +\t\t\t  << std::setfill('0') << buffer->sequence()\n> > +\t\t\t  << \" buf: \" << buffer->index()\n> > +\t\t\t  << \" bytesused: \" << buffer->bytesused()\n> > +\t\t\t  << \" timestamp: \" << buffer->timestamp()\n> > +\t\t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n> > +\t\t\t  << std::endl;\n> >\n> > -\tif (writer)\n> > -\t\twriter->write(buffer);\n> > +\t\tif (writer)\n> > +\t\t\twriter->write(buffer, name);\n> > +\t}\n> >\n> >  \trequest = camera->createRequest();\n> >  \tif (!request) {\n> > --\n> > 2.21.0\n> >\n> > _______________________________________________\n> > libcamera-devel mailing list\n> > libcamera-devel@lists.libcamera.org\n> > https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-lf1-x12b.google.com (mail-lf1-x12b.google.com\n\t[IPv6:2a00:1450:4864:20::12b])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0B5DE610BF\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  4 Apr 2019 02:05:16 +0200 (CEST)","by mail-lf1-x12b.google.com with SMTP id o19so410956lfl.4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 03 Apr 2019 17:05:16 -0700 (PDT)","from localhost (89-233-230-99.cust.bredband2.com. [89.233.230.99])\n\tby smtp.gmail.com with ESMTPSA id\n\tz29sm3237492lfg.52.2019.04.03.17.05.14\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tWed, 03 Apr 2019 17:05:14 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to\n\t:user-agent; bh=cFcQKEy2UmIctFV/nHeIBr6aJ0sKJB5Yovbo2Dci1Po=;\n\tb=vGfNDYajZI29hKD5UJuPYA+5ksEIbL9DpJUUxsfAtPq6E6DNeJIbIGS7N2ZQI6F8kd\n\t1Y2YGI1z3j/gTIyHAwGvfgswewvRWPBXghpeFirP/FJtj/sC/68yU0BKu4isJFOO/ZiA\n\tnXiyzyfxKbMqR3WYNtWAXDTINZZhQxnLS4TelfPWGJH8jVfClWIoksOKhA4YHAzKrsi5\n\tHxzk0u/ph72rfCOi70MBzdabxwzxkXTn+ZO+K/xK9KNPOouXACvPyvi6hrY8RhUlqD+q\n\t+vRI4iuAQySQS2zq1tWFzJojv8O7V+KHga4gdkDanyqCWjjTkUU1tNk51w0t/4yKP0vK\n\tuXDg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to:user-agent;\n\tbh=cFcQKEy2UmIctFV/nHeIBr6aJ0sKJB5Yovbo2Dci1Po=;\n\tb=XP+yuuDxYojtomGytUl6E5KT/XO+Y3m8Z+XhvlHTSCGQKHOmJ8iZo33KiBhSDy78jK\n\t/37iIaaFGSoxjwVUe4BfCB9SHCkqI85qhRdAuT4TRnFQxaspw5SaIpcXkujjPr3VLbml\n\tRQEhe2JzexXxl6CaHE9taKDStvvJ7zXaiFQD3iIPyaf6lmCSfyt4X37xM6eQOzv/8bvm\n\tXTdaeNdVGlA0fu8gi8GaGQD5v0VOBeJZtlO+Tks485sMLeCihVeBNuYlGoBgGYD+SluC\n\t0zpaToZNawWSJ85Tsc7nto4331Ipq+8pgMJhqF2922OYTGVhJdUFFi0K9eQkijQragQS\n\t9GHg==","X-Gm-Message-State":"APjAAAUPEbG4bGonu0XeCdu3nLA+3anerMNyfYjuotgGpv/b22KPsLPr\n\tbR021j1vNkLCLQeWNd7vLoKl8A==","X-Google-Smtp-Source":"APXvYqxVPfqQX4H7O5uF9vXP2Av6cxDwzd3ixBXTtI1V2Qr3rpaiVT+0WB0zziGcSjXtGZqL6N77tQ==","X-Received":"by 2002:ac2:569b:: with SMTP id 27mr1427167lfr.24.1554336315476; \n\tWed, 03 Apr 2019 17:05:15 -0700 (PDT)","Date":"Thu, 4 Apr 2019 02:05:14 +0200","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190404000514.GM23466@bigcity.dyn.berto.se>","References":"<20190403011235.12782-1-niklas.soderlund@ragnatech.se>\n\t<20190403011235.12782-4-niklas.soderlund@ragnatech.se>\n\t<20190403140541.7sjpfcmude4r332p@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190403140541.7sjpfcmude4r332p@uno.localdomain>","User-Agent":"Mutt/1.11.3 (2019-02-01)","Subject":"Re: [libcamera-devel] [PATCH v2 3/4] cam: Extend request completion\n\thandler to deal with multiple streams","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Thu, 04 Apr 2019 00:05:16 -0000"}},{"id":1296,"web_url":"https://patchwork.libcamera.org/comment/1296/","msgid":"<20190405223859.GC15350@bigcity.dyn.berto.se>","date":"2019-04-05T22:38:59","subject":"Re: [libcamera-devel] [PATCH v2 3/4] cam: Extend request completion\n\thandler to deal with multiple streams","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Jacopo,\n\nThanks for your feedback,\n\nOn 2019-04-03 16:44:10 +0200, Jacopo Mondi wrote:\n> Hi Niklas,\n> \n> On Wed, Apr 03, 2019 at 03:12:34AM +0200, Niklas Söderlund wrote:\n> > The completion handler needs to handle all buffers in the request. Solve\n> > this by iterating over all buffers in the completed request and assign\n> > each stream a name as we encounter them. The buffer writer needs to be\n> > extended to learn about stream names so it can prefix the files it\n> > writes with it.\n> >\n> > Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> > ---\n> >  src/cam/buffer_writer.cpp |  5 +++--\n> >  src/cam/buffer_writer.h   |  2 +-\n> >  src/cam/main.cpp          | 42 ++++++++++++++++++++++++++++-----------\n> >  3 files changed, 34 insertions(+), 15 deletions(-)\n> >\n> > diff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp\n> > index 2d2258b4cd1cbbc2..b82ffaded688226a 100644\n> > --- a/src/cam/buffer_writer.cpp\n> > +++ b/src/cam/buffer_writer.cpp\n> > @@ -19,13 +19,14 @@ BufferWriter::BufferWriter(const std::string &pattern)\n> >  {\n> >  }\n> >\n> > -int BufferWriter::write(libcamera::Buffer *buffer)\n> > +int BufferWriter::write(libcamera::Buffer *buffer,\n> > +\t\t\tconst std::string &streamName)\n> >  {\n> >  \tstd::string filename;\n> >  \tsize_t pos;\n> >  \tint fd, ret = 0;\n> >\n> > -\tfilename = pattern_;\n> > +\tfilename = streamName + \"-\" + pattern_;\n> \n> this should be the other way around, otherwise I get:\n> stream1-/tmp/frame-#\n\nThanks for reporting this usage, I had not thought about that. I have \ntaken Laurent's suggestion and add the streamName together with the \nsequence number while expanding the #.\n\n> \n> FYI I sent this exact same patch in my v4 imgu+multi stream series:\n> \"[PATCH v4 28/31] src: cam: Add output name to frame writer\"\n> where I handle multiple stream requests too, as I assume you have not\n> seen that series.\n\nI had not noticed that patch no :-(\n\n> \n> thanks\n>   j\n> \n> \n> >  \tpos = filename.find_first_of('#');\n> >  \tif (pos != std::string::npos) {\n> >  \t\tstd::stringstream ss;\n> > diff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h\n> > index 9705773e0e397d45..7bf785d1e83235ff 100644\n> > --- a/src/cam/buffer_writer.h\n> > +++ b/src/cam/buffer_writer.h\n> > @@ -16,7 +16,7 @@ class BufferWriter\n> >  public:\n> >  \tBufferWriter(const std::string &pattern = \"frame-#.bin\");\n> >\n> > -\tint write(libcamera::Buffer *buffer);\n> > +\tint write(libcamera::Buffer *buffer, const std::string &streamName);\n> >\n> >  private:\n> >  \tstd::string pattern_;\n> > diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> > index b47bda21cbb7f220..9af7907a3d937c28 100644\n> > --- a/src/cam/main.cpp\n> > +++ b/src/cam/main.cpp\n> > @@ -145,28 +145,46 @@ static int prepareCameraConfig(std::map<Stream *, StreamConfiguration> *config)\n> >  \treturn 0;\n> >  }\n> >\n> > +static std::string streamToName(const Stream *stream)\n> > +{\n> > +\tstatic std::map<const Stream *, std::string> names;\n> > +\n> > +\tif (names.find(stream) == names.end())\n> > +\t\tnames[stream] = std::string(\"stream\") + std::to_string(names.size());\n> > +\n> > +\treturn names[stream];\n> > +}\n> > +\n> >  static void requestComplete(Request *request, const std::map<Stream *, Buffer *> &buffers)\n> >  {\n> >  \tstatic uint64_t last = 0;\n> > +\tdouble fps = 0.0;\n> >\n> >  \tif (request->status() == Request::RequestCancelled)\n> >  \t\treturn;\n> >\n> > -\tBuffer *buffer = buffers.begin()->second;\n> > +\tfor (auto it = buffers.begin(); it != buffers.end(); ++it) {\n> > +\t\tStream *stream = it->first;\n> > +\t\tBuffer *buffer = it->second;\n> > +\t\tstd::string name = streamToName(stream);\n> >\n> > -\tdouble fps = buffer->timestamp() - last;\n> > -\tfps = last && fps ? 1000000000.0 / fps : 0.0;\n> > -\tlast = buffer->timestamp();\n> > +\t\tif (it == buffers.begin()) {\n> > +\t\t\tfps = buffer->timestamp() - last;\n> > +\t\t\tfps = last && fps ? 1000000000.0 / fps : 0.0;\n> > +\t\t\tlast = buffer->timestamp();\n> > +\t\t}\n> >\n> > -\tstd::cout << \"seq: \" << std::setw(6) << std::setfill('0') << buffer->sequence()\n> > -\t\t  << \" buf: \" << buffer->index()\n> > -\t\t  << \" bytesused: \" << buffer->bytesused()\n> > -\t\t  << \" timestamp: \" << buffer->timestamp()\n> > -\t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n> > -\t\t  << std::endl;\n> > +\t\tstd::cout << name << \" seq: \" << std::setw(6)\n> > +\t\t\t  << std::setfill('0') << buffer->sequence()\n> > +\t\t\t  << \" buf: \" << buffer->index()\n> > +\t\t\t  << \" bytesused: \" << buffer->bytesused()\n> > +\t\t\t  << \" timestamp: \" << buffer->timestamp()\n> > +\t\t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n> > +\t\t\t  << std::endl;\n> >\n> > -\tif (writer)\n> > -\t\twriter->write(buffer);\n> > +\t\tif (writer)\n> > +\t\t\twriter->write(buffer, name);\n> > +\t}\n> >\n> >  \trequest = camera->createRequest();\n> >  \tif (!request) {\n> > --\n> > 2.21.0\n> >\n> > _______________________________________________\n> > libcamera-devel mailing list\n> > libcamera-devel@lists.libcamera.org\n> > https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-lf1-x132.google.com (mail-lf1-x132.google.com\n\t[IPv6:2a00:1450:4864:20::132])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B537C60DB3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat,  6 Apr 2019 00:39:01 +0200 (CEST)","by mail-lf1-x132.google.com with SMTP id g7so5448203lfh.10\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 05 Apr 2019 15:39:01 -0700 (PDT)","from localhost (89-233-230-99.cust.bredband2.com. [89.233.230.99])\n\tby smtp.gmail.com with ESMTPSA id\n\ti24sm4574409lfl.73.2019.04.05.15.38.59\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tFri, 05 Apr 2019 15:39:00 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to\n\t:user-agent; bh=EQQZOUUC4bSbOf43uKk8618Jn/PyOtHw7gvqdwuKpKA=;\n\tb=TTf4EI1zlFS3wb28qrhybrW1T+/D4lJn47vMiPqyY36Z7KPvEX4SXoNv67hw15GauV\n\tYPDOq5+rBK7r01BdNKm8LAYw/wUKobO18l5Ah7IGpX/jPQzaH2p/zQQ18nYwSNFHDiip\n\tr3QrbuUnQn+TFo2dJP9VNmbriLYHKkPaNSxm0ko980EFjwKkJaCHxRo6XQnMRGC24y6a\n\tyalUiIsR9uqHkkvyobhFlKpJX9TLhmDUrAkHhUkSpTCslao8kAfs4IE4ChpgEyR0nQPq\n\thb5kOW3iwLx2EpMo6lao2XMjcqwCxUL/illhw8RgXqmweCXoFjNLELkIKlZV0c+pnYhV\n\tNfUA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to:user-agent;\n\tbh=EQQZOUUC4bSbOf43uKk8618Jn/PyOtHw7gvqdwuKpKA=;\n\tb=j70bza9kVCDm4gbOKF/Dav0tGN7ftt0+RmD/IfbhXh90dqydfDHs6hwoduEziWUVpV\n\twxef087kzrW78/3rN6NrW/Mh6nrs/8BDHRtR2PC+bIFt7g+okm/uNUsXwC57ZZJi5yy6\n\taf6fPdqYgzC136vH9aiOxNeia3xatVeezIKzbSVXgZKGbTuRh7joepAK9ekSpng+6Pzp\n\tp56OQnEorN2UVitiBAjoOohyzYxtE17meFOgK+jTk+Uw6Azjib1tZOAP94CEtMpWLMQS\n\tGBXwpdJkdqm+/J/b/Owlmo5GTVcCXOj8yHgQ18YlpzDxNs74id3YRc6tBIlUu4zOF1NI\n\t3SMQ==","X-Gm-Message-State":"APjAAAWJniEraCUydupbTRjuhEjeMyMAI12ObY+jINxp7BDkU6D847pv\n\tmsbu6W5GyMxF5fxHH/5IOYodK9/68Zg=","X-Google-Smtp-Source":"APXvYqza0mPZhW8W8ejFFyi4vYykFR/w2FQ9L/cq3adAXYZHu95uKiPgehHNIH21ecyO3FN1RTskjA==","X-Received":"by 2002:ac2:554a:: with SMTP id l10mr2569300lfk.49.1554503941056;\n\tFri, 05 Apr 2019 15:39:01 -0700 (PDT)","Date":"Sat, 6 Apr 2019 00:38:59 +0200","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190405223859.GC15350@bigcity.dyn.berto.se>","References":"<20190403011235.12782-1-niklas.soderlund@ragnatech.se>\n\t<20190403011235.12782-4-niklas.soderlund@ragnatech.se>\n\t<20190403144410.ctl3e45qav37wpk7@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190403144410.ctl3e45qav37wpk7@uno.localdomain>","User-Agent":"Mutt/1.11.3 (2019-02-01)","Subject":"Re: [libcamera-devel] [PATCH v2 3/4] cam: Extend request completion\n\thandler to deal with multiple streams","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Fri, 05 Apr 2019 22:39:02 -0000"}}]