Untitled
unknown
plain_text
6 months ago
5.9 kB
3
Indexable
import PyNvCodec as nvc import numpy as np import av # PyAV library import os import time from concurrent.futures import ThreadPoolExecutor, as_completed import glob def process_video(input_video_path, output_video_path, gpu_id=0, bitrate='1M'): try: if not os.path.isfile(input_video_path): print(f"Input file does not exist: {input_video_path}") return print(f"Processing {input_video_path} on GPU {gpu_id}...") # Initialize the decoder nvDec = nvc.PyNvDecoder(input_video_path, gpu_id) # Get video properties width = nvDec.Width() height = nvDec.Height() fps_in = nvDec.Framerate() fps_out = fps_in codec = 'h264' # Optionally reduce resolution new_width = (width // 4) # Ensure width is even new_height = (height // 4) # Ensure height is even print(f"Original resolution: {width}x{height}, Output resolution: {new_width}x{new_height}") # Use PyAV to get input time base input_container = av.open(input_video_path) input_stream = input_container.streams.video[0] input_time_base = input_stream.time_base input_container.close() # Initialize the encoder with desired settings enc_params = { 'preset': 'P1', # Fastest preset 'codec': codec, 's': f'{new_width}x{new_height}', # Force encoder scaling 'bitrate': bitrate, 'fps': str(int(fps_out)), 'profile': 'baseline', 'rc': 'cbr', 'gop': '500', } nvEnc = nvc.PyNvEncoder(enc_params, gpu_id) # Ensure output directory exists os.makedirs(os.path.dirname(output_video_path), exist_ok=True) # Initialize PyAV container and stream output_container = av.open(output_video_path, mode='w') av_codec = 'h264_nvenc' if codec == 'h264' else 'hevc_nvenc' stream = output_container.add_stream(av_codec, rate=int(fps_out)) stream.width = new_width stream.height = new_height stream.pix_fmt = 'yuv420p' stream.time_base = input_time_base # Initialize packet buffer and packet data packet = np.empty(0, dtype=np.uint8) pkt_data = nvc.PacketData() # Create PySurfaceResizer to resize frames on GPU resizer = nvc.PySurfaceResizer(new_width, new_height, nvc.PixelFormat.NV12, gpu_id) # Processing loop last_output_pts = None while True: # Decode a single surface with packet data surface = nvDec.DecodeSingleSurface(pkt_data) if surface.Empty(): break # Resize surface on GPU resized_surface = resizer.Execute(surface) if resized_surface.Empty(): print("Failed to resize surface.") continue # Confirm resized dimensions #print(f"Resized surface dimensions: {resized_surface.Width()}x{resized_surface.Height()}") # Encode the resized surface success = nvEnc.EncodeSingleSurface(resized_surface, packet) if not success: continue if packet.size > 0: output_pts = pkt_data.pts if last_output_pts is not None and output_pts <= last_output_pts: output_pts = last_output_pts + 1 last_output_pts = output_pts av_packet = av.packet.Packet(packet.tobytes()) av_packet.stream = stream av_packet.pts = output_pts av_packet.dts = output_pts output_container.mux(av_packet) # Flush the encoder while True: success = nvEnc.FlushSinglePacket(packet) if not success or packet.size == 0: break output_pts = (last_output_pts + 1) if last_output_pts is not None else 0 last_output_pts = output_pts av_packet = av.packet.Packet(packet.tobytes()) av_packet.stream = stream av_packet.pts = output_pts av_packet.dts = output_pts output_container.mux(av_packet) # Close the output container output_container.close() print(f"Processed: {input_video_path} -> {output_video_path}") except Exception as e: print(f"An error occurred while processing {input_video_path}: {e}") def main(): input_dir = 'in_movies/stream' output_dir = 'out_movies/compressed_stream' os.makedirs(output_dir, exist_ok=True) # List of video files to process video_files = glob.glob(os.path.join(input_dir, '*')) print(f"Found {len(video_files)} video files to process:") for vf in video_files: print(f" - {vf}") start_time = time.time() # Specify available GPU IDs for cycling gpu_ids = [0, 1] # Change based on your system's available GPUs max_workers = len(gpu_ids) # One worker per GPU # Parallel processing with ThreadPoolExecutor with ThreadPoolExecutor(max_workers=max_workers) as executor: futures = [] for index, input_file in enumerate(video_files): filename = os.path.basename(input_file) output_file = os.path.join(output_dir, filename) gpu_id = gpu_ids[index % len(gpu_ids)] # Cycle through GPUs futures.append(executor.submit(process_video, input_file, output_file, gpu_id)) # Track completion for future in as_completed(futures): try: future.result() print("Processing completed for a video.") except Exception as e: print(f"An error occurred: {e}") total_time = time.time() - start_time print(f"All files processed in {total_time:.2f} seconds.") if __name__ == '__main__': main()
Editor is loading...
Leave a Comment