| 136 | class avcodec_software_encode_device_t: public platf::avcodec_encode_device_t { |
| 137 | public: |
| 138 | int convert(platf::img_t &img) override { |
| 139 | // If we need to add aspect ratio padding, we need to scale into an intermediate output buffer |
| 140 | bool requires_padding = (sw_frame->width != sws_output_frame->width || sw_frame->height != sws_output_frame->height); |
| 141 | |
| 142 | // Setup the input frame using the caller's img_t |
| 143 | sws_input_frame->data[0] = img.data; |
| 144 | sws_input_frame->linesize[0] = img.row_pitch; |
| 145 | |
| 146 | // Perform color conversion and scaling to the final size |
| 147 | auto status = sws_scale_frame(sws.get(), requires_padding ? sws_output_frame.get() : sw_frame.get(), sws_input_frame.get()); |
| 148 | if (status < 0) { |
| 149 | char string[AV_ERROR_MAX_STRING_SIZE]; |
| 150 | BOOST_LOG(error) << "Couldn't scale frame: "sv << av_make_error_string(string, AV_ERROR_MAX_STRING_SIZE, status); |
| 151 | return -1; |
| 152 | } |
| 153 | |
| 154 | // If we require aspect ratio padding, copy the output frame into the final padded frame |
| 155 | if (requires_padding) { |
| 156 | auto fmt_desc = av_pix_fmt_desc_get((AVPixelFormat) sws_output_frame->format); |
| 157 | auto planes = av_pix_fmt_count_planes((AVPixelFormat) sws_output_frame->format); |
| 158 | for (int plane = 0; plane < planes; plane++) { |
| 159 | auto shift_h = plane == 0 ? 0 : fmt_desc->log2_chroma_h; |
| 160 | auto shift_w = plane == 0 ? 0 : fmt_desc->log2_chroma_w; |
| 161 | auto offset = ((offsetW >> shift_w) * fmt_desc->comp[plane].step) + (offsetH >> shift_h) * sw_frame->linesize[plane]; |
| 162 | |
| 163 | // Copy line-by-line to preserve leading padding for each row |
| 164 | for (int line = 0; line < sws_output_frame->height >> shift_h; line++) { |
| 165 | memcpy(sw_frame->data[plane] + offset + (line * sw_frame->linesize[plane]), sws_output_frame->data[plane] + (line * sws_output_frame->linesize[plane]), (size_t) (sws_output_frame->width >> shift_w) * fmt_desc->comp[plane].step); |
| 166 | } |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | // If frame is not a software frame, it means we still need to transfer from main memory |
| 171 | // to vram memory |
| 172 | if (frame->hw_frames_ctx) { |
| 173 | auto status = av_hwframe_transfer_data(frame, sw_frame.get(), 0); |
| 174 | if (status < 0) { |
| 175 | char string[AV_ERROR_MAX_STRING_SIZE]; |
| 176 | BOOST_LOG(error) << "Failed to transfer image data to hardware frame: "sv << av_make_error_string(string, AV_ERROR_MAX_STRING_SIZE, status); |
| 177 | return -1; |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | return 0; |
| 182 | } |
| 183 | |
| 184 | int set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) override { |
| 185 | this->frame = frame; |