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

There are still broken pipe errors #2337

Open
F4k3r22 opened this issue Jan 21, 2025 · 3 comments
Open

There are still broken pipe errors #2337

F4k3r22 opened this issue Jan 21, 2025 · 3 comments
Labels
bug Issues that report (apparent) bugs.

Comments

@F4k3r22
Copy link

F4k3r22 commented Jan 21, 2025

There should be no more broken pipes

There are still broken pipe errors

I come to rescue this FFMPEG error from the broken pipe, because I have noticed when I have been doing tests and deployments that the error occurs at a certain memory usage of the system, the initial system I have is 8GB of RAM and if I pass the 6.5GB of use it throws this same error:

Moviepy - Building video /tmp/output/video.mp4.
MoviePy - Writing audio in /tmp/output/temp-audio.mp3
MoviePy - Done.
Moviepy - Writing video /tmp/output/video.mp4

t: 8%|███████████▏ | 48/624 [00:06<06:34, 1.46it/s, now=None]Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/moviepy/video/io/ffmpeg_writer.py", line 136, in write_frame
self.proc.stdin.write(img_array.tobytes())
BrokenPipeError: [Errno 32] Broken pipe

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/srv/yt1/lambda_function.py", line 424, in
lambda_handler("", "")
File "/srv/yt1/lambda_function.py", line 422, in lambda_handler
cm.CreateMP4(upload_to_yt)
File "/srv/yt1/lambda_function.py", line 371, in CreateMP4
f1.write_videofile(file, fps = 24 , temp_audiofile=os.path.join(DIR_PATH_OUTPUT, 'temp-audio.mp3' ))
File "", line 2, in write_videofile
File "/usr/local/lib/python3.10/dist-packages/moviepy/decorators.py", line 54, in requires_duration
return f(clip, *a, **k)
File "", line 2, in write_videofile
File "/usr/local/lib/python3.10/dist-packages/moviepy/decorators.py", line 135, in use_clip_fps_by_default
return f(clip, *new_a, **new_kw)
File "", line 2, in write_videofile
File "/usr/local/lib/python3.10/dist-packages/moviepy/decorators.py", line 22, in convert_masks_to_RGB
return f(clip, *a, **k)
File "/usr/local/lib/python3.10/dist-packages/moviepy/video/VideoClip.py", line 300, in write_videofile
ffmpeg_write_video(self, filename, fps, codec,
File "/usr/local/lib/python3.10/dist-packages/moviepy/video/io/ffmpeg_writer.py", line 228, in ffmpeg_write_video
writer.write_frame(frame)
File "/usr/local/lib/python3.10/dist-packages/moviepy/video/io/ffmpeg_writer.py", line 180, in write_frame
raise IOError(error)
OSError: [Errno 32] Broken pipe

MoviePy error: FFMPEG encountered the following error while writing file /tmp/output/video.mp4
<!-- Please include code that demonstrates this problem so that we can reproduce it. For advice on how to do this, see https://stackoverflow.com/help/mcve

It's higlhy helpfull if you can provide an exact and complete code reproducing the bug, *along with all necessary medias (videos, images, sounds, etc.).* 

Ideally you should provide a functional code snippet that maintainers can run to investigate the bug. 

And investigating a little more it turns out that the continuous use of final_video.write_videofile(
str(output_path),
fps=24,
threads=64,
codec='libx264',
audio_codec='aac',
)
The memory is not cleaned correctly to be able to make a continuous execution of my App, so I had to implement an automatic memory cleaning to avoid that, but sometimes I still get the same error because my cleaning functions are not sufficient.
-->

Used medias

Specifications

  • Python Version: 3.10.13
  • MoviePy Version: 2.1.2
  • Platform Name:
  • Platform Version:
@F4k3r22 F4k3r22 added the bug Issues that report (apparent) bugs. label Jan 21, 2025
@OsaAjani
Copy link
Collaborator

Could you please provide code and medias to reproduce the problem ?

@davidxiaodev
Copy link

davidxiaodev commented Feb 9, 2025

My below error doesn't happen with source from master branch when preview, but got error after close the video

I got the same error with 10 minutes tutorial, it happens when preview every time(on Mac15.3 (24D60)), but it works in notebook with display_in_notebook:

Lets import moviepy, lets also import numpy we will use it a some point

from moviepy import *
import numpy as np

#################

VIDEO LOADING

#################

We load our video

video = VideoFileClip("./resources/bbb.mp4")

#####################

SCENES EXTRACTION

#####################

We extract the scenes we want to use

First the characters

intro_clip = video.subclipped(1, 11)
bird_clip = video.subclipped(16, 20)
bunny_clip = video.subclipped(37, 55)
rodents_clip = video.subclipped(
"00:03:34.75", "00:03:56"
) # we can also use string notation with format HH:MM:SS.uS
rambo_clip = video.subclipped("04:41.5", "04:44.70")

#####################

SCENES PREVIEWING

#####################

Now, lets have a first look at our clips

Warning: you need ffplay installed for preview to work

We set a low fps so our machine can render in real time without slowing down

intro_clip.preview(fps=20)
bird_clip.preview(fps=20)
bunny_clip.preview(fps=20)
rodents_clip.preview(fps=20)
rambo_clip.preview(fps=20)

Traceback (most recent call last):
File "/home/vscode/.local/lib/python3.10/site-packages/moviepy/audio/io/ffplay_audiopreviewer.py", line 60, in write_frames
self.proc.stdin.write(frames_array.tobytes()) =====>>this line failed, with "broken pipe", root reason
BrokenPipeError: [Errno 32] Broken pipe

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/usr/local/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
self.run()
File "/usr/local/lib/python3.10/threading.py", line 953, in run
self._target(*self._args, **self._kwargs)
File "/home/vscode/.local/lib/python3.10/site-packages/decorator.py", line 232, in fun
return caller(func, *(extras + args), **kw)
File "/home/vscode/.local/lib/python3.10/site-packages/moviepy/decorators.py", line 53, in requires_duration
return func(clip, *args, **kwargs)
File "/home/vscode/.local/lib/python3.10/site-packages/moviepy/audio/AudioClip.py", line 301, in audiopreview
ffplay_audiopreview(
File "/home/vscode/.local/lib/python3.10/site-packages/decorator.py", line 232, in fun
return caller(func, *(extras + args), **kw)
File "/home/vscode/.local/lib/python3.10/site-packages/moviepy/decorators.py", line 53, in requires_duration
return func(clip, *args, **kwargs)
File "/home/vscode/.local/lib/python3.10/site-packages/moviepy/audio/io/ffplay_audiopreviewer.py", line 155, in ffplay_audiopreview
previewer.write_frames(chunk)
File "/home/vscode/.local/lib/python3.10/site-packages/moviepy/audio/io/ffplay_audiopreviewer.py", line 68, in write_frames
self.logfile.seek(0)
AttributeError: 'FFPLAY_AudioPreviewer' object has no attribute 'logfile' ====> another issue, logfile not exist,

@koljanos
Copy link

koljanos commented Feb 11, 2025

I will also get occasional broken pipes:

@shared_task(bind=True)
def process_video_moviepy(self, excavation_video_id):
    self.update_state(state='PROGRESS', meta={'current': 1, 'total': 4, 'description': 'Start processing'})
    try:
        excavation_video = ExcavationVideo.objects.get(id=excavation_video_id)
        excavation_video.error_message = None
        excavation_video.save(update_fields=['error_message'])
        target_fps = None
        target_bitrate = None
        if excavation_video.metadata['fps'] < 25 and excavation_video.metadata['bitrate'] < 1500000:
            excavation_video.finished = True
            self.update_state(state='PROGRESS', meta={'current': 4, 'total': 4, 'description': 'Saving file'})
            excavation_video.save(update_fields=['video', 'finished'])
            return {
                "status": "success",
                "output_video": {
                    "url": excavation_video.video.url,
                    "name": excavation_video.video.name,
                    "size": excavation_video.video.size
                }
            }
        elif excavation_video.metadata['fps'] > 25:
            target_fps = 25
        elif excavation_video.metadata['bitrate'] > 1500000:
            target_bitrate = 1500000

        if not excavation_video.video:
            raise ValueError("No source video attached")

        storage = excavation_video.video.storage
        self.update_state(state='PROGRESS', meta={'current': 2, 'total': 4, 'description': 'Loading file'})

        with tempfile.TemporaryDirectory() as tmpdir:
            tmp_path = Path(tmpdir)
            input_path = tmp_path / excavation_video.video.name.split('/')[-1]
            output_filename = f"processed_{Path(excavation_video.video.name).stem}.mp4"
            output_path = tmp_path / output_filename

            # Download source video to temp location
            with storage.open(excavation_video.video.name, 'rb') as source_file:
                with open(input_path, 'wb') as temp_file:
                    temp_file.write(source_file.read())

            # MoviePy processing

            self.update_state(state='PROGRESS', meta={'current': 3, 'total': 4, 'description': 'Processing with MoviePy'})
            
            clip = VideoFileClip(str(input_path))
            
            # Calculate target resolution
            original_width, original_height = clip.size
            cheeky_width, cheeky_height = video_wh(str(input_path))
            if cheeky_width != original_width or cheeky_height != original_height:
                original_width, original_height = original_height, original_width

            if original_width < original_height:  # Portrait
                if original_height >= 3840:
                    max_w, max_h = 720, 1280
                else:
                    max_w, max_h = original_width, original_height
            else:  # Landscape
                if original_width >= 3840:
                    max_w, max_h = 1280, 720
                else:
                    max_w, max_h = original_width, original_height

            ratio = min(max_w / original_width, max_h / original_height)
            if ratio < 1:  # Only apply scaling if needed
                new_w = round(original_width * ratio)
                new_h = round(original_height * ratio)
            else:  # Keep original but ensure even
                new_w, new_h = original_width, original_height
            # Ensure even dimensions
            new_w = new_w // 2 * 2
            new_h = new_h // 2 * 2
            if original_width >= 3840:
                processed = clip.resize(width = new_w)
            elif original_height >= 3840:
                processed = clip.resize(height = new_h)
            else:
                processed = clip

            if target_fps is not None:
                processed = processed.with_fps(25)
            else:
                pass
            # Export with specified parameters
            if target_bitrate is not None:
                processed.write_videofile(
                    str(output_path),
                    codec='libx264',
                    bitrate='1500k',
                    preset='fast',
                    audio_codec='aac',
                    ffmpeg_params=[
                        '-movflags', '+faststart',
                        # '-pix_fmt', 'yuv420p', 

                    ],
                    threads = 1
                )
            else:
                processed.write_videofile(
                    str(output_path),
                    codec='libx264',  # Explicitly set codec to ensure compatibility
                    preset='fast',
                    audio_codec='aac',  # Ensure audio is retained
                    ffmpeg_params=[
                        '-movflags', '+faststart',
                        # '-pix_fmt', 'yuv420p',

                    ],
                    threads = 1
                )
            clip.close()
            processed.close()
            del clip, processed
            gc.collect()

            # if not output_path.exists():
            #     raise FileNotFoundError("Output video file was not generated")

            # Save processed video
            with open(output_path, 'rb') as processed_file:
                excavation_video.video.save(
                    output_filename,
                    File(processed_file)
                )
                excavation_video.finished = True
                self.update_state(state='PROGRESS', meta={'current': 4, 'total': 4, 'description': 'Saving file'})
                excavation_video.save(update_fields=['video', 'finished'])
            counter = 0
            for proc in psutil.process_iter(attrs=['pid', 'name']):
                if "ffmpeg" in proc.info['name']:
                    counter += 1
                    proc.kill()  # Kill stale processes
            return {
                "status": "success",
                "output_video": {
                    "url": excavation_video.video.url,
                    "name": excavation_video.video.name,
                    "size": excavation_video.video.size,
                    "counter": counter
                }
            }

Tried to mitigate the error, by killing all ffmpeg processes after I do the conversion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issues that report (apparent) bugs.
Projects
None yet
Development

No branches or pull requests

4 participants