Search code examples
pythonopencvmp4

could not find a writer for the specified extension in function 'cv::imwrite_' - filename HAS the correct extension - Python, CV2


I originally tried holding the thumbnails in memory, but that didn't work and now I'm creating temporary thumbnail files in a nearby directory. Anyway, the image creation works for photos, but it's failing for mp4 video and I'm not sure why. This is the error:

'D:\\Stuff\\Pictures\\Transit\\20230729_020700.mp4'
'D:\\Stuff\\Pictures\\Transit\\thumbs\\20230729_020700.mp4'
{'name': '20230729_020700', 'ext': 'mp4', 'name_ext': '20230729_020700.mp4', 'type': 'movie', 'dtime': '20230729_140700', 'width': 1920, 'height': 1080}
Traceback (most recent call last):
  File "C:\stuff\Working\htdocs\PSSort\picsort\main.py", line 179, in <module>
    list_dest_dir()
  File "C:\stuff\Working\htdocs\PSSort\picsort\main.py", line 108, in list_dest_dir
    this_file = get_file_deets(file)
                ^^^^^^^^^^^^^^^^^^^^
  File "C:\stuff\Working\htdocs\PSSort\picsort\main.py", line 71, in get_file_deets
    cv2.imwrite(thumb_path,frame)
cv2.error: OpenCV(4.8.1) D:\a\opencv-python\opencv-python\opencv\modules\imgcodecs\src\loadsave.cpp:696: error: (-2:Unspecified error) could not find a writer for the specified extension in function 'cv::imwrite_'

In my code, I've put prints to show that the input file and output file names and paths are correct AND have the extension (which I stress because every post I could find on this error was always because someone forgot the extension). So what do I do when the extension is fine?

Code is below:

#input a filename. Something.jpg, thisisamov.mp4, etc.
#output adds an entry 
def get_file_deets(name):

    if settings['dest_dir'][-1] == '\\':
        full_path_filename = settings['dest_dir']+name
        thumb_path = settings['dest_dir']+'thumbs\\'+name
    else:
        full_path_filename = settings['dest_dir']+'\\'+name
        thumb_path = settings['dest_dir']+'\\thumbs\\'+name

    pre_r(full_path_filename)
    pre_r(thumb_path)

    temp = {}
    temp['name'], temp['ext'] = name.rsplit('.')
    # keep track of the whole name
    temp['name_ext'] = name
    if temp['ext'] != 'mp4':
        image = Image.open(full_path_filename)
        temp['type'] = 'image'
        # Grab it's "taken on" date
        exif = image.getexif();
        temp['dtime'] = exif.get(306).replace(":", "").replace(' ','_')
        temp['width'],temp['height'] = image.size
        # first make a thumbnail, then B64 THAT (not the whole image)
        image.thumbnail((100,100))
        image.save(thumb_path)
        image.close()
    else:
        temp['type'] = 'movie'
        temp['dtime'] = datetime.fromtimestamp(os.path.getmtime(full_path_filename)).strftime("%Y%m%d %H%M%S").replace(' ','_')
        probe = ffmpeg.probe(full_path_filename)
        video_streams = [stream for stream in probe["streams"] if stream["codec_type"] == "video"][0]
        temp['width'], temp['height'] = video_streams['width'], video_streams['height']
        pre_r(temp)
        # Time in seconds where you want to capture the thumbnail (e.g., 10 seconds)
        thumbnail_time = 10
        cap = cv2.VideoCapture(full_path_filename)
        cap.set(cv2.CAP_PROP_POS_MSEC, thumbnail_time * 1000)
        ret, frame = cap.read()
        if ret:
            cv2.imwrite(thumb_path,frame)
        cap.release()

    temp['size'] = f"{os.path.getsize(full_path_filename)/1000000:.2f}MBs"
    return temp

Bonus: I'd love to know a cleaner way to do that if statement at the beginning. I toyed with a ternary, but it was ugly so I gave up on that.


Solution

  • Ok, I went over this again and realized that I'm trying to save a thumbnail as an mp4 which is obviously wrong. I want a THUMBNAIL... ergo a photo. I altered the code to make the thumbnail path the filename_vid.jpg and it works flawlessly.