Streamed annotation responses
Closed this issue · 1 comments
mzur commented
We had a case of a long video where the request to get all video annotations ran into the memory limit. To avoid this we can send a streamed JSON response and fetch the annotations lazily in chunks. Here is a proof of concept for the VideoAnnotationController:
public function index(Request $request, $id)
{
$video = Video::findOrFail($id);
$this->authorize('access', $video);
$user = $request->user();
$session = $video->volume->getActiveAnnotationSession($user);
$load = ['labels.label', 'labels.user'];
if ($session) {
return $session->getVolumeFileAnnotations($video, $user)->load($load);
}
$yieldAnnotations = function () use ($video, $load): \Generator {
foreach ($video->annotations()->with($load)->lazy() as $annotation) {
yield $annotation;
}
};
return response()->streamJson($yieldAnnotations());
}
The same could be done in the ImageAnnotationController.
In the proof of concept above the streaming does not work if there is an active annotation session. The getVolumeFileAnnotations()
method of an annotation session has to be updated to support streaming like that.
mzur commented
Here is an example how a streamed response can be tested:
$response = $this
->getJson("/api/v1/videos/{$this->video->id}/annotations")
->assertStatus(200);
ob_start();
$response->sendContent();
$content = ob_get_clean();
$response = new \Illuminate\Testing\TestResponse(
new \Symfony\Component\HttpFoundation\Response($content,
$response->baseResponse->getStatusCode(),
$response->baseResponse->headers->all()
)
);
$response->assertJsonFragment(['frames' => [1.0]])
->assertJsonFragment(['points' => [[10, 20]]])
->assertJsonFragment(['color' => 'bada55'])
->assertJsonFragment(['name' => 'My label']);