Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to find a suitable output format for 'temp-file' #28

Closed
ericnjogu opened this issue Dec 12, 2019 · 5 comments
Closed

Unable to find a suitable output format for 'temp-file' #28

ericnjogu opened this issue Dec 12, 2019 · 5 comments

Comments

@ericnjogu
Copy link

I am trying to read a video file and write it to a socket using the code below and it is failing. I would appreciate your help:

async def write_video_to_stream(path_to_video, path_to_socket):
    video_reader = imageio.get_reader(path_to_video)
    sock = await create_socket(path_to_socket)
    _, socket_writer = await asyncio.open_unix_connection(sock=sock)
    img_writer = imageio.get_writer(socket_writer, format='FFMPEG', ffmpeg_log_level='debug')
    for frame in video_reader:
        img_writer.append_data(frame)
        #await socket_writer.drain()
    img_writer.close()
    socket_writer.close()

The code is failing with the stacktrace below (debug logging turned on):

(object-detection) mugo@eric-aspire:~/ai-object-detection/detection-visualization$ python socket_stream.py ~/Videos/dog-rescue-water.mp4 /tmp/sock2
ffmpeg version 4.1-static https://johnvansickle.com/ffmpeg/  Copyright (c) 2000-2018 the FFmpeg developers
  built with gcc 6.3.0 (Debian 6.3.0-18+deb9u1) 20170516
  configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc-6 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gray --enable-libaom --enable-libfribidi --enable-libass --enable-libvmaf --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libvorbis --enable-libopus --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg
  libavutil      56. 22.100 / 56. 22.100
  libavcodec     58. 35.100 / 58. 35.100
  libavformat    58. 20.100 / 58. 20.100
  libavdevice    58.  5.100 / 58.  5.100
  libavfilter     7. 40.101 /  7. 40.101
  libswscale      5.  3.100 /  5.  3.100
  libswresample   3.  3.100 /  3.  3.100
  libpostproc    55.  3.100 / 55.  3.100
Splitting the commandline.
Reading option '-y' ... matched as option 'y' (overwrite output files) with argument '1'.
Reading option '-f' ... matched as option 'f' (force format) with argument 'rawvideo'.
Reading option '-vcodec' ... matched as option 'vcodec' (force video codec ('copy' to copy stream)) with argument 'rawvideo'.
Reading option '-s' ... matched as option 's' (set frame size (WxH or abbreviation)) with argument '400x400'.
Reading option '-pix_fmt' ... matched as option 'pix_fmt' (set pixel format) with argument 'rgb24'.
Reading option '-r' ... matched as option 'r' (set frame rate (Hz value, fraction or abbreviation)) with argument '10.00'.
Reading option '-i' ... matched as input url with argument '-'.
Reading option '-an' ... matched as option 'an' (disable audio) with argument '1'.
Reading option '-vcodec' ... matched as option 'vcodec' (force video codec ('copy' to copy stream)) with argument 'libx264'.
Reading option '-pix_fmt' ... matched as option 'pix_fmt' (set pixel format) with argument 'yuv420p'.
Reading option '-crf' ... matched as AVOption 'crf' with argument '25'.
Reading option '-v' ... matched as option 'v' (set logging level) with argument 'debug'.
Reading option '/tmp/imageio_8sv61nse' ... matched as output url.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option y (overwrite output files) with argument 1.
Applying option v (set logging level) with argument debug.
Successfully parsed a group of options.
Parsing a group of options: input url -.
Applying option f (force format) with argument rawvideo.
Applying option vcodec (force video codec ('copy' to copy stream)) with argument rawvideo.
Applying option s (set frame size (WxH or abbreviation)) with argument 400x400.
Applying option pix_fmt (set pixel format) with argument rgb24.
Applying option r (set frame rate (Hz value, fraction or abbreviation)) with argument 10.00.
Successfully parsed a group of options.
Opening an input file: -.
[rawvideo @ 0x6584d00] Opening 'pipe:' for reading
[pipe @ 0x6585680] Setting default whitelist 'crypto'
[rawvideo @ 0x6584d00] Before avformat_find_stream_info() pos: 0 bytes read:32768 seeks:0 nb_streams:1
[rawvideo @ 0x6584d00] All info found
[rawvideo @ 0x6584d00] After avformat_find_stream_info() pos: 480000 bytes read:480000 seeks:0 frames:1
Input #0, rawvideo, from 'pipe:':
  Duration: N/A, start: 0.000000, bitrate: 38400 kb/s
    Stream #0:0, 1, 1/10: Video: rawvideo, 1 reference frame (RGB[24] / 0x18424752), rgb24, 400x400, 0/1, 38400 kb/s, 10 tbr, 10 tbn, 10 tbc
Successfully opened the file.
Parsing a group of options: output url /tmp/imageio_8sv61nse.
Applying option an (disable audio) with argument 1.
Applying option vcodec (force video codec ('copy' to copy stream)) with argument libx264.
Applying option pix_fmt (set pixel format) with argument yuv420p.
Successfully parsed a group of options.
Opening an output file: /tmp/imageio_8sv61nse.
[NULL @ 0x65870c0] Unable to find a suitable output format for '/tmp/imageio_8sv61nse'
/tmp/imageio_8sv61nse: Invalid argument
[AVIOContext @ 0x6585500] Statistics: 480000 bytes read, 0 seeks
Fatal read error on socket transport
protocol: <asyncio.streams.StreamReaderProtocol object at 0x7fa09efcc2b0>
transport: <_SelectorSocketTransport fd=7 read=polling write=<idle, bufsize=0>>
Traceback (most recent call last):
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/asyncio/selector_events.py", line 801, in _read_ready__data_received
    data = self._sock.recv(self.max_size)
OSError: [Errno 22] Invalid argument
Traceback (most recent call last):
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/site-packages/imageio_ffmpeg/_io.py", line 411, in write_frames
    p.stdin.write(bb)
BrokenPipeError: [Errno 32] Broken pipe

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "socket_stream.py", line 33, in <module>
    asyncio.run(write_video_to_stream(ns.path_to_video, ns.path_to_socket))
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "socket_stream.py", line 11, in write_video_to_stream
    img_writer.append_data(frame)
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/site-packages/imageio/core/format.py", line 492, in append_data
    return self._append_data(im, total_meta)
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/site-packages/imageio/plugins/ffmpeg.py", line 572, in _append_data
    self._write_gen.send(im)
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/site-packages/imageio_ffmpeg/_io.py", line 418, in write_frames
    raise IOError(msg)
OSError: [Errno 32] Broken pipe

FFMPEG COMMAND:
/home/mugo/miniconda3/envs/object-detection/lib/python3.7/site-packages/imageio_ffmpeg/binaries/ffmpeg-linux64-v4.1 -y -f rawvideo -vcodec rawvideo -s 400x400 -pix_fmt rgb24 -r 10.00 -i - -an -vcodec libx264 -pix_fmt yuv420p -crf 25 -v debug /tmp/imageio_8sv61nse

FFMPEG STDERR OUTPUT:

Fatal Python error: could not acquire lock for <_io.BufferedReader name=11> at interpreter shutdown, possibly due to daemon threads

Thread 0x00007fa0a65a0700 (most recent call first):
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/site-packages/imageio_ffmpeg/_parsing.py", line 61 in run
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/threading.py", line 917 in _bootstrap_inner
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/threading.py", line 885 in _bootstrap

Current thread 0x00007fa0aad6d740 (most recent call first):
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/subprocess.py", line 1704 in _communicate
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/subprocess.py", line 939 in communicate
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/site-packages/imageio_ffmpeg/_io.py", line 193 in read_frames
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/site-packages/imageio/plugins/ffmpeg.py", line 343 in _close
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/site-packages/imageio/core/format.py", line 252 in close
  File "/home/mugo/miniconda3/envs/object-detection/lib/python3.7/site-packages/imageio/core/format.py", line 241 in __del__
Aborted (core dumped)
@almarklein
Copy link
Member

Thanks for the report!

Imageio-ffmpeg only supports writing to a file on the file system, because it calls ffmpeg in a subprocess. Therefore imageio cannot write directly to a file-like object (like a socket). What happens is that ffmpeg is used to write the video to a temporary file, and then it's loaded and written to the file object. This happens about here in imageio/core/request.py.

Now, this error looks a bit like ffmpeg needs a filename extension to determine the output format, and the temp file does not have such an extension. This can be reproduced:

import imageio
import imageio_ffmpeg

ims = imageio.mimread("imageio:cockatoo.mp4", memtest="1000MB")
size = ims[0].shape[1], ims[0].shape[0]

gen = imageio_ffmpeg.write_frames("c:/users/almar/desktop/foo_video_no_ext", size)
gen.send(None)
for im in ims:
    gen.send(im)
gen.close()

@almarklein
Copy link
Member

Now how to fix this. The quick version would be to use imageio_ffmpeg directly.

The longer version would probably be to change Request.get_local_filename() here to accept an optional argument to allow plugins to specify a file extension.

ericnjogu added a commit to ericnjogu/object-detection-visualization that referenced this issue Jan 8, 2020
@ericnjogu
Copy link
Author

Thanks for the response @almarklein and sorry for the long delay.

I tried out your suggestion and it appears that imageio_ffmpeg write_frames() only works with string paths. It would be nice to have it accept file like objects too. This way one could write to a socket.

Here's my code - ericnjogu/object-detection-visualization@0e14220

@almarklein
Copy link
Member

It would be nice to have it accept file like objects too

I agree, but this is not possible because we're calling ffmpeg in a subprocess and all we can do is give it a file path. It would likely be possible if we'd use ffmpeg as a library, but this makes packaging much harder; it was a deliberate choice to use ffmpeg as a subprocess.

@almarklein
Copy link
Member

I created imageio/imageio#509 in imageio to fix the issue with the temp file. But then I realized that it won't actually fix your problem: you want to be able to stream video to a file like object, and imageio-ffmpeg simply cannot do that. I've added a note to the readme that explains this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants