1

我正在尝试从大约 400 个视频中构建一个大视频,但是我遇到了“打开的文件太多”的问题。我已经阅读了文档(并看到了这篇文章)。

但是我仍然遇到同样的错误:OSError: [Errno 24] Too many open files

我已经调查过,如果我已经用 方法删除了每个打开的电影,我不知道还能做什么close_files

编码:

from moviepy.editor import *
import json
import os
import urllib
import shutil
import re
import api.constants
import traceback
from api.constants import *
import datetime
import string


def close_files(files):
    for file in files:
        try:
            if not (isinstance(file,ImageClip) or isinstance(file,TextClip)):
                del file.reader
            del file
        except Exception,e:
            print "Exception: "+str(e)

def max_text(title,author):
    return title
    #if len(title) > 120:
    #    return title[0:(120- len(author))]+"..."
    #else:
    #    return title

def clean(text):
    return ''.join(filter(lambda x: x in string.printable, text))

def compile_videos(fileName,serverjson,post_to):
    try:
        now = datetime.datetime.now()
        print "Starting at: "+str(now)

        #Video's dimensions
        w = 1440
        h = 1440
        videoDimension = w,h

        #Video offset
        videoOffset = 580
        titleOffset = 0

        #Movie dimensions
        w2 = 2560
        h2 = 1440
        movieDimensions = w2,h2

        #Title dimensions
        w3 = 540
        h3 = 1440
        titleDimensions = w3,h3

        #Left Holder Dimension
        holderDimensions = 500,500
        holderPosition = 50,450


        #Holder
        left_holder = ImageClip("assets/everyday_icon.png").set_position(holderPosition)
        if post_to=="7min":
            left_holder = ImageClip("assets/7min_icon.png").set_position(holderPosition)
        elif post_to=="7x7":
            left_holder = ImageClip("assets/7x7_icon.png").set_position(holderPosition)

        #Temporal directory
        directory = 'tmp'
        if os.path.exists(directory):
          shutil.rmtree(directory)
        if not os.path.exists(directory):
          os.makedirs(directory)

        #Read Videos/Files

        data = serverjson

        videos_and_subtitles = []
        #We add the holder so that there's always a background
        videos_and_subtitles.append(left_holder)

        currentDuration = 0
        videoId = ""
        preprocessedVideos = []
        counter = 0
        videoNumber = 0
        print "Total videos: "+str(len(data["videos"]))
        for videoObject in data["videos"]:
            counter+=1
            #Download video and thumbnail
            downloader=urllib.URLopener()
            videoId = videoObject[API_VIDEO_ID]
            videoPath = directory+"/"+str(videoObject[API_VIDEO_ID])+'_video.mp4'
            thumbPath = directory+"/"+str(videoObject[API_VIDEO_ID])+'_thumb.jpg'
            try:
                downloader.retrieve(str(videoObject[API_VIDEO_URL]),videoPath)
                downloader.retrieve(str(videoObject[API_THUMB_URL]),thumbPath)
            except Exception,e:
                print "Exception: "+str(e)
                print "Video ID: "+str(videoId)
                traceback.print_exc()
                continue
            #Create new video and update video duration's offset
            newVideo = VideoFileClip(videoPath).resize(height=w,width=h).set_position((videoOffset,titleOffset)).set_start(currentDuration)
            #Append new video to videos

            videos_and_subtitles.append(newVideo)
            #Append subtitle to Subtitles
            videoName = clean(videoObject[API_NAME])
            videoAuthor = clean(videoObject[API_AUTHOR])
            newSubtitleText = clean(max_text(videoName,videoAuthor)+" \n\n"+videoObject[API_AUTHOR])
            newSubtitle = ( TextClip(newSubtitleText,fontsize=70,color='white',font='Helvetica-Narrow',align='center',method='caption',size=titleDimensions).set_start(currentDuration).set_position((videoOffset+w,0)).set_duration(newVideo.duration) )
            videos_and_subtitles.append(newSubtitle)
            currentDuration+=newVideo.duration

            #Preprocess videos
            if counter%50==0 or len(data["videos"])==(counter):
                currentFilename=directory+"/"+str(videoNumber)+fileName
                result = CompositeVideoClip(videos_and_subtitles,size=movieDimensions,bg_color=(0,164,119)).set_duration(currentDuration).write_videofile(filename=currentFilename,preset='ultrafast',fps=24)
                preprocessedVideos.append(VideoFileClip(currentFilename))
                close_files(videos_and_subtitles)
                videos_and_subtitles = []
                currentDuration = 0
                videoNumber+=1
                if (videoObject==data["videos"][-1]):
                    break
            print "Next video"

        print "Compiling video"
        result = concatenate_videoclips(preprocessedVideos).write_videofile(filename=directory+"/"+fileName,preset='ultrafast')
        #result = CompositeVideoClip(videos_and_subtitles,size=movieDimensions,bg_color=(0,164,119)).set_duration(currentDuration).write_videofile(filename=directory+"/"+fileName,preset='ultrafast')
        print "Video Compiled"
        now = datetime.datetime.now()
        print "Finished at: "+str(now)
        return fileName
    except Exception,e:
        print "Exception: "+str(e)
        print "Video ID: "+str(videoId)
        traceback.print_exc()
        return None

我正在分批处理 50 个文件,因为如果我以较小的批次进行处理,则需要更长的时间。问题不在于一次打开 50 个文件。问题发生在第一批或第二批(处理约 100-150 个文件)之后,这表明文件未关闭(否则第一批将无法正确处理)。这意味着如果我分 10 批执行同样的操作,只是文件没有正确关闭

像这样的其他帖子,你可以看到答案:

您的测试脚本会覆盖 f 每次迭代,这意味着文件每次都会关闭。使用管道记录到文件和子进程都会用完描述符,这可能会导致耗尽。

不太适用,因为我每 50 次迭代覆盖一次实例,但是我仍然遇到问题。

此外,我不能在 VideoFileClip 上调用“关闭”。

4

0 回答 0