Add a frame to the queue waiting to be encoded.
| 64 | |
| 65 | // Add a frame to the queue waiting to be encoded. |
| 66 | void ChunkWriter::WriteFrame(std::shared_ptr<openshot::Frame> frame) |
| 67 | { |
| 68 | // Check for open reader (or throw exception) |
| 69 | if (!is_open) |
| 70 | throw WriterClosed("The ChunkWriter is closed. Call Open() before calling this method.", path); |
| 71 | |
| 72 | // Check if currently writing chunks? |
| 73 | if (!is_writing) |
| 74 | { |
| 75 | // Save thumbnail of chunk start frame |
| 76 | frame->Save(get_chunk_path(chunk_count, "", ".jpeg"), 1.0); |
| 77 | |
| 78 | // Create FFmpegWriter (FINAL quality) |
| 79 | create_folder(get_chunk_path(chunk_count, "final", "")); |
| 80 | writer_final = new FFmpegWriter(get_chunk_path(chunk_count, "final", default_extension)); |
| 81 | writer_final->SetAudioOptions(true, default_acodec, info.sample_rate, info.channels, info.channel_layout, 128000); |
| 82 | writer_final->SetVideoOptions(true, default_vcodec, info.fps, info.width, info.height, info.pixel_ratio, false, false, info.video_bit_rate); |
| 83 | |
| 84 | // Create FFmpegWriter (PREVIEW quality) |
| 85 | create_folder(get_chunk_path(chunk_count, "preview", "")); |
| 86 | writer_preview = new FFmpegWriter(get_chunk_path(chunk_count, "preview", default_extension)); |
| 87 | writer_preview->SetAudioOptions(true, default_acodec, info.sample_rate, info.channels, info.channel_layout, 128000); |
| 88 | writer_preview->SetVideoOptions(true, default_vcodec, info.fps, info.width * 0.5, info.height * 0.5, info.pixel_ratio, false, false, info.video_bit_rate * 0.5); |
| 89 | |
| 90 | // Create FFmpegWriter (LOW quality) |
| 91 | create_folder(get_chunk_path(chunk_count, "thumb", "")); |
| 92 | writer_thumb = new FFmpegWriter(get_chunk_path(chunk_count, "thumb", default_extension)); |
| 93 | writer_thumb->SetAudioOptions(true, default_acodec, info.sample_rate, info.channels, info.channel_layout, 128000); |
| 94 | writer_thumb->SetVideoOptions(true, default_vcodec, info.fps, info.width * 0.25, info.height * 0.25, info.pixel_ratio, false, false, info.video_bit_rate * 0.25); |
| 95 | |
| 96 | // Prepare Streams |
| 97 | writer_final->PrepareStreams(); |
| 98 | writer_preview->PrepareStreams(); |
| 99 | writer_thumb->PrepareStreams(); |
| 100 | |
| 101 | // Write header |
| 102 | writer_final->WriteHeader(); |
| 103 | writer_preview->WriteHeader(); |
| 104 | writer_thumb->WriteHeader(); |
| 105 | |
| 106 | // Keep track that a chunk is being written |
| 107 | is_writing = true; |
| 108 | last_frame_needed = true; |
| 109 | } |
| 110 | |
| 111 | // If this is not the 1st chunk, always start frame 1 with the last frame from the previous |
| 112 | // chunk. This helps to prevent audio resampling issues (because it "stokes" the sample array) |
| 113 | if (last_frame_needed) |
| 114 | { |
| 115 | if (last_frame) |
| 116 | { |
| 117 | // Write the previous chunks LAST FRAME to the current chunk |
| 118 | writer_final->WriteFrame(last_frame); |
| 119 | writer_preview->WriteFrame(last_frame); |
| 120 | writer_thumb->WriteFrame(last_frame); |
| 121 | } else { |
| 122 | // Write the 1st frame (of the 1st chunk)... since no previous chunk is available |
| 123 | auto blank_frame = std::make_shared<Frame>( |
no test coverage detected