| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of FFmpeg. | ||
| 3 | * | ||
| 4 | * FFmpeg is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU Lesser General Public | ||
| 6 | * License as published by the Free Software Foundation; either | ||
| 7 | * version 2.1 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * Lesser General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU Lesser General Public | ||
| 15 | * License along with FFmpeg; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | /** | ||
| 20 | * @file | ||
| 21 | * Frame multithreading support functions | ||
| 22 | * @see doc/multithreading.txt | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <stdatomic.h> | ||
| 26 | |||
| 27 | #include "avcodec.h" | ||
| 28 | #include "avcodec_internal.h" | ||
| 29 | #include "codec_desc.h" | ||
| 30 | #include "codec_internal.h" | ||
| 31 | #include "decode.h" | ||
| 32 | #include "hwaccel_internal.h" | ||
| 33 | #include "hwconfig.h" | ||
| 34 | #include "internal.h" | ||
| 35 | #include "packet_internal.h" | ||
| 36 | #include "pthread_internal.h" | ||
| 37 | #include "libavutil/refstruct.h" | ||
| 38 | #include "thread.h" | ||
| 39 | #include "threadframe.h" | ||
| 40 | #include "version_major.h" | ||
| 41 | |||
| 42 | #include "libavutil/avassert.h" | ||
| 43 | #include "libavutil/buffer.h" | ||
| 44 | #include "libavutil/common.h" | ||
| 45 | #include "libavutil/cpu.h" | ||
| 46 | #include "libavutil/frame.h" | ||
| 47 | #include "libavutil/internal.h" | ||
| 48 | #include "libavutil/log.h" | ||
| 49 | #include "libavutil/mem.h" | ||
| 50 | #include "libavutil/opt.h" | ||
| 51 | #include "libavutil/thread.h" | ||
| 52 | |||
| 53 | enum { | ||
| 54 | /// Set when the thread is awaiting a packet. | ||
| 55 | STATE_INPUT_READY, | ||
| 56 | /// Set before the codec has called ff_thread_finish_setup(). | ||
| 57 | STATE_SETTING_UP, | ||
| 58 | /// Set after the codec has called ff_thread_finish_setup(). | ||
| 59 | STATE_SETUP_FINISHED, | ||
| 60 | }; | ||
| 61 | |||
| 62 | enum { | ||
| 63 | UNINITIALIZED, ///< Thread has not been created, AVCodec->close mustn't be called | ||
| 64 | NEEDS_CLOSE, ///< FFCodec->close needs to be called | ||
| 65 | INITIALIZED, ///< Thread has been properly set up | ||
| 66 | }; | ||
| 67 | |||
| 68 | typedef struct DecodedFrames { | ||
| 69 | AVFrame **f; | ||
| 70 | size_t nb_f; | ||
| 71 | size_t nb_f_allocated; | ||
| 72 | } DecodedFrames; | ||
| 73 | |||
| 74 | typedef struct ThreadFrameProgress { | ||
| 75 | atomic_int progress[2]; | ||
| 76 | } ThreadFrameProgress; | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Context used by codec threads and stored in their AVCodecInternal thread_ctx. | ||
| 80 | */ | ||
| 81 | typedef struct PerThreadContext { | ||
| 82 | struct FrameThreadContext *parent; | ||
| 83 | |||
| 84 | pthread_t thread; | ||
| 85 | int thread_init; | ||
| 86 | unsigned pthread_init_cnt;///< Number of successfully initialized mutexes/conditions | ||
| 87 | pthread_cond_t input_cond; ///< Used to wait for a new packet from the main thread. | ||
| 88 | pthread_cond_t progress_cond; ///< Used by child threads to wait for progress to change. | ||
| 89 | pthread_cond_t output_cond; ///< Used by the main thread to wait for frames to finish. | ||
| 90 | |||
| 91 | pthread_mutex_t mutex; ///< Mutex used to protect the contents of the PerThreadContext. | ||
| 92 | pthread_mutex_t progress_mutex; ///< Mutex used to protect frame progress values and progress_cond. | ||
| 93 | |||
| 94 | AVCodecContext *avctx; ///< Context used to decode packets passed to this thread. | ||
| 95 | |||
| 96 | AVPacket *avpkt; ///< Input packet (for decoding) or output (for encoding). | ||
| 97 | |||
| 98 | /** | ||
| 99 | * Decoded frames from a single decode iteration. | ||
| 100 | */ | ||
| 101 | DecodedFrames df; | ||
| 102 | int result; ///< The result of the last codec decode/encode() call. | ||
| 103 | |||
| 104 | atomic_int state; | ||
| 105 | |||
| 106 | int die; ///< Set when the thread should exit. | ||
| 107 | |||
| 108 | int hwaccel_serializing; | ||
| 109 | int async_serializing; | ||
| 110 | |||
| 111 | // set to 1 in ff_thread_finish_setup() when a threadsafe hwaccel is used; | ||
| 112 | // cannot check hwaccel caps directly, because | ||
| 113 | // worked threads clear hwaccel state for thread-unsafe hwaccels | ||
| 114 | // after each decode call | ||
| 115 | int hwaccel_threadsafe; | ||
| 116 | |||
| 117 | atomic_int debug_threads; ///< Set if the FF_DEBUG_THREADS option is set. | ||
| 118 | } PerThreadContext; | ||
| 119 | |||
| 120 | /** | ||
| 121 | * Context stored in the client AVCodecInternal thread_ctx. | ||
| 122 | */ | ||
| 123 | typedef struct FrameThreadContext { | ||
| 124 | PerThreadContext *threads; ///< The contexts for each thread. | ||
| 125 | PerThreadContext *prev_thread; ///< The last thread submit_packet() was called on. | ||
| 126 | |||
| 127 | unsigned pthread_init_cnt; ///< Number of successfully initialized mutexes/conditions | ||
| 128 | pthread_mutex_t buffer_mutex; ///< Mutex used to protect get/release_buffer(). | ||
| 129 | /** | ||
| 130 | * This lock is used for ensuring threads run in serial when thread-unsafe | ||
| 131 | * hwaccel is used. | ||
| 132 | */ | ||
| 133 | pthread_mutex_t hwaccel_mutex; | ||
| 134 | pthread_mutex_t async_mutex; | ||
| 135 | pthread_cond_t async_cond; | ||
| 136 | int async_lock; | ||
| 137 | |||
| 138 | DecodedFrames df; | ||
| 139 | int result; | ||
| 140 | |||
| 141 | /** | ||
| 142 | * Packet to be submitted to the next thread for decoding. | ||
| 143 | */ | ||
| 144 | AVPacket *next_pkt; | ||
| 145 | |||
| 146 | int next_decoding; ///< The next context to submit a packet to. | ||
| 147 | int next_finished; ///< The next context to return output from. | ||
| 148 | |||
| 149 | /* hwaccel state for thread-unsafe hwaccels is temporarily stored here in | ||
| 150 | * order to transfer its ownership to the next decoding thread without the | ||
| 151 | * need for extra synchronization */ | ||
| 152 | const AVHWAccel *stash_hwaccel; | ||
| 153 | void *stash_hwaccel_context; | ||
| 154 | void *stash_hwaccel_priv; | ||
| 155 | } FrameThreadContext; | ||
| 156 | |||
| 157 | 1818 | static int hwaccel_serial(const AVCodecContext *avctx) | |
| 158 | { | ||
| 159 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1818 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
1818 | return avctx->hwaccel && !(ffhwaccel(avctx->hwaccel)->caps_internal & HWACCEL_CAP_THREAD_SAFE); |
| 160 | } | ||
| 161 | |||
| 162 | 842 | static void async_lock(FrameThreadContext *fctx) | |
| 163 | { | ||
| 164 | 842 | pthread_mutex_lock(&fctx->async_mutex); | |
| 165 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 842 times.
|
842 | while (fctx->async_lock) |
| 166 | ✗ | pthread_cond_wait(&fctx->async_cond, &fctx->async_mutex); | |
| 167 | 842 | fctx->async_lock = 1; | |
| 168 | 842 | pthread_mutex_unlock(&fctx->async_mutex); | |
| 169 | 842 | } | |
| 170 | |||
| 171 | 842 | static void async_unlock(FrameThreadContext *fctx) | |
| 172 | { | ||
| 173 | 842 | pthread_mutex_lock(&fctx->async_mutex); | |
| 174 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 842 times.
|
842 | av_assert0(fctx->async_lock); |
| 175 | 842 | fctx->async_lock = 0; | |
| 176 | 842 | pthread_cond_broadcast(&fctx->async_cond); | |
| 177 | 842 | pthread_mutex_unlock(&fctx->async_mutex); | |
| 178 | 842 | } | |
| 179 | |||
| 180 | 76 | static void thread_set_name(PerThreadContext *p) | |
| 181 | { | ||
| 182 | 76 | AVCodecContext *avctx = p->avctx; | |
| 183 | 76 | int idx = p - p->parent->threads; | |
| 184 | char name[16]; | ||
| 185 | |||
| 186 | 76 | snprintf(name, sizeof(name), "av:%.7s:df%d", avctx->codec->name, idx); | |
| 187 | |||
| 188 | 76 | ff_thread_setname(name); | |
| 189 | 76 | } | |
| 190 | |||
| 191 | // get a free frame to decode into | ||
| 192 | 1144 | static AVFrame *decoded_frames_get_free(DecodedFrames *df) | |
| 193 | { | ||
| 194 |
2/2✓ Branch 0 taken 163 times.
✓ Branch 1 taken 981 times.
|
1144 | if (df->nb_f == df->nb_f_allocated) { |
| 195 | 163 | AVFrame **tmp = av_realloc_array(df->f, df->nb_f + 1, | |
| 196 | sizeof(*df->f)); | ||
| 197 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 163 times.
|
163 | if (!tmp) |
| 198 | ✗ | return NULL; | |
| 199 | 163 | df->f = tmp; | |
| 200 | |||
| 201 | 163 | df->f[df->nb_f] = av_frame_alloc(); | |
| 202 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 163 times.
|
163 | if (!df->f[df->nb_f]) |
| 203 | ✗ | return NULL; | |
| 204 | |||
| 205 | 163 | df->nb_f_allocated++; | |
| 206 | } | ||
| 207 | |||
| 208 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1144 times.
|
1144 | av_assert0(!df->f[df->nb_f]->buf[0]); |
| 209 | |||
| 210 | 1144 | return df->f[df->nb_f]; | |
| 211 | } | ||
| 212 | |||
| 213 | 537 | static void decoded_frames_pop(DecodedFrames *df, AVFrame *dst) | |
| 214 | { | ||
| 215 | 537 | AVFrame *tmp_frame = df->f[0]; | |
| 216 | 537 | av_frame_move_ref(dst, tmp_frame); | |
| 217 | 537 | memmove(df->f, df->f + 1, (df->nb_f - 1) * sizeof(*df->f)); | |
| 218 | 537 | df->f[--df->nb_f] = tmp_frame; | |
| 219 | 537 | } | |
| 220 | |||
| 221 | ✗ | static void decoded_frames_flush(DecodedFrames *df) | |
| 222 | { | ||
| 223 | ✗ | for (size_t i = 0; i < df->nb_f; i++) | |
| 224 | ✗ | av_frame_unref(df->f[i]); | |
| 225 | ✗ | df->nb_f = 0; | |
| 226 | ✗ | } | |
| 227 | |||
| 228 | 86 | static void decoded_frames_free(DecodedFrames *df) | |
| 229 | { | ||
| 230 |
2/2✓ Branch 0 taken 163 times.
✓ Branch 1 taken 86 times.
|
249 | for (size_t i = 0; i < df->nb_f_allocated; i++) |
| 231 | 163 | av_frame_free(&df->f[i]); | |
| 232 | 86 | av_freep(&df->f); | |
| 233 | 86 | df->nb_f = 0; | |
| 234 | 86 | df->nb_f_allocated = 0; | |
| 235 | 86 | } | |
| 236 | |||
| 237 | /** | ||
| 238 | * Codec worker thread. | ||
| 239 | * | ||
| 240 | * Automatically calls ff_thread_finish_setup() if the codec does | ||
| 241 | * not provide an update_thread_context method, or if the codec returns | ||
| 242 | * before calling it. | ||
| 243 | */ | ||
| 244 | 76 | static attribute_align_arg void *frame_worker_thread(void *arg) | |
| 245 | { | ||
| 246 | 76 | PerThreadContext *p = arg; | |
| 247 | 76 | AVCodecContext *avctx = p->avctx; | |
| 248 | 76 | const FFCodec *codec = ffcodec(avctx->codec); | |
| 249 | |||
| 250 | 76 | thread_set_name(p); | |
| 251 | |||
| 252 | 76 | pthread_mutex_lock(&p->mutex); | |
| 253 | 606 | while (1) { | |
| 254 | int ret; | ||
| 255 | |||
| 256 |
4/4✓ Branch 0 taken 754 times.
✓ Branch 1 taken 606 times.
✓ Branch 2 taken 678 times.
✓ Branch 3 taken 76 times.
|
1360 | while (atomic_load(&p->state) == STATE_INPUT_READY && !p->die) |
| 257 | 678 | pthread_cond_wait(&p->input_cond, &p->mutex); | |
| 258 | |||
| 259 |
2/2✓ Branch 0 taken 76 times.
✓ Branch 1 taken 606 times.
|
682 | if (p->die) break; |
| 260 | |||
| 261 |
2/2✓ Branch 0 taken 494 times.
✓ Branch 1 taken 112 times.
|
606 | if (!codec->update_thread_context) |
| 262 | 494 | ff_thread_finish_setup(avctx); | |
| 263 | |||
| 264 | /* If a decoder supports hwaccel, then it must call ff_get_format(). | ||
| 265 | * Since that call must happen before ff_thread_finish_setup(), the | ||
| 266 | * decoder is required to implement update_thread_context() and call | ||
| 267 | * ff_thread_finish_setup() manually. Therefore the above | ||
| 268 | * ff_thread_finish_setup() call did not happen and hwaccel_serializing | ||
| 269 | * cannot be true here. */ | ||
| 270 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
|
606 | av_assert0(!p->hwaccel_serializing); |
| 271 | |||
| 272 | /* if the previous thread uses thread-unsafe hwaccel then we take the | ||
| 273 | * lock to ensure the threads don't run concurrently */ | ||
| 274 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 606 times.
|
606 | if (hwaccel_serial(avctx)) { |
| 275 | ✗ | pthread_mutex_lock(&p->parent->hwaccel_mutex); | |
| 276 | ✗ | p->hwaccel_serializing = 1; | |
| 277 | } | ||
| 278 | |||
| 279 | 606 | ret = 0; | |
| 280 |
2/2✓ Branch 0 taken 1144 times.
✓ Branch 1 taken 606 times.
|
1750 | while (ret >= 0) { |
| 281 | AVFrame *frame; | ||
| 282 | |||
| 283 | /* get the frame which will store the output */ | ||
| 284 | 1144 | frame = decoded_frames_get_free(&p->df); | |
| 285 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1144 times.
|
1144 | if (!frame) { |
| 286 | ✗ | p->result = AVERROR(ENOMEM); | |
| 287 | ✗ | goto alloc_fail; | |
| 288 | } | ||
| 289 | |||
| 290 | /* do the actual decoding */ | ||
| 291 | 1144 | ret = ff_decode_receive_frame_internal(avctx, frame); | |
| 292 |
2/2✓ Branch 0 taken 538 times.
✓ Branch 1 taken 606 times.
|
1144 | if (ret == 0) |
| 293 | 538 | p->df.nb_f++; | |
| 294 |
2/4✓ Branch 0 taken 606 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 606 times.
|
606 | else if (ret < 0 && frame->buf[0]) |
| 295 | ✗ | av_frame_unref(frame); | |
| 296 | |||
| 297 |
2/2✓ Branch 0 taken 606 times.
✓ Branch 1 taken 538 times.
|
1144 | p->result = (ret == AVERROR(EAGAIN)) ? 0 : ret; |
| 298 | } | ||
| 299 | |||
| 300 |
2/2✓ Branch 0 taken 578 times.
✓ Branch 1 taken 28 times.
|
606 | if (atomic_load(&p->state) == STATE_SETTING_UP) |
| 301 | 28 | ff_thread_finish_setup(avctx); | |
| 302 | |||
| 303 | 578 | alloc_fail: | |
| 304 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
|
606 | if (p->hwaccel_serializing) { |
| 305 | /* wipe hwaccel state for thread-unsafe hwaccels to avoid stale | ||
| 306 | * pointers lying around; | ||
| 307 | * the state was transferred to FrameThreadContext in | ||
| 308 | * ff_thread_finish_setup(), so nothing is leaked */ | ||
| 309 | ✗ | avctx->hwaccel = NULL; | |
| 310 | ✗ | avctx->hwaccel_context = NULL; | |
| 311 | ✗ | avctx->internal->hwaccel_priv_data = NULL; | |
| 312 | |||
| 313 | ✗ | p->hwaccel_serializing = 0; | |
| 314 | ✗ | pthread_mutex_unlock(&p->parent->hwaccel_mutex); | |
| 315 | } | ||
| 316 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
606 | av_assert0(!avctx->hwaccel || |
| 317 | (ffhwaccel(avctx->hwaccel)->caps_internal & HWACCEL_CAP_THREAD_SAFE)); | ||
| 318 | |||
| 319 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
|
606 | if (p->async_serializing) { |
| 320 | ✗ | p->async_serializing = 0; | |
| 321 | |||
| 322 | ✗ | async_unlock(p->parent); | |
| 323 | } | ||
| 324 | |||
| 325 | 606 | pthread_mutex_lock(&p->progress_mutex); | |
| 326 | |||
| 327 | 606 | atomic_store(&p->state, STATE_INPUT_READY); | |
| 328 | |||
| 329 | 606 | pthread_cond_broadcast(&p->progress_cond); | |
| 330 | 606 | pthread_cond_signal(&p->output_cond); | |
| 331 | 606 | pthread_mutex_unlock(&p->progress_mutex); | |
| 332 | } | ||
| 333 | 76 | pthread_mutex_unlock(&p->mutex); | |
| 334 | |||
| 335 | 76 | return NULL; | |
| 336 | } | ||
| 337 | |||
| 338 | /** | ||
| 339 | * Update the next thread's AVCodecContext with values from the reference thread's context. | ||
| 340 | * | ||
| 341 | * @param dst The destination context. | ||
| 342 | * @param src The source context. | ||
| 343 | * @param for_user 0 if the destination is a codec thread, 1 if the destination is the user's thread | ||
| 344 | * @return 0 on success, negative error code on failure | ||
| 345 | */ | ||
| 346 | 1111 | static int update_context_from_thread(AVCodecContext *dst, const AVCodecContext *src, int for_user) | |
| 347 | { | ||
| 348 | 1111 | const FFCodec *const codec = ffcodec(dst->codec); | |
| 349 | 1111 | int err = 0; | |
| 350 | |||
| 351 |
5/6✓ Branch 0 taken 1111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 555 times.
✓ Branch 3 taken 556 times.
✓ Branch 4 taken 108 times.
✓ Branch 5 taken 447 times.
|
1111 | if (dst != src && (for_user || codec->update_thread_context)) { |
| 352 | 664 | dst->time_base = src->time_base; | |
| 353 | 664 | dst->framerate = src->framerate; | |
| 354 | 664 | dst->width = src->width; | |
| 355 | 664 | dst->height = src->height; | |
| 356 | 664 | dst->pix_fmt = src->pix_fmt; | |
| 357 | 664 | dst->sw_pix_fmt = src->sw_pix_fmt; | |
| 358 | |||
| 359 | 664 | dst->coded_width = src->coded_width; | |
| 360 | 664 | dst->coded_height = src->coded_height; | |
| 361 | |||
| 362 | 664 | dst->has_b_frames = src->has_b_frames; | |
| 363 | 664 | dst->idct_algo = src->idct_algo; | |
| 364 | #if FF_API_CODEC_PROPS | ||
| 365 | FF_DISABLE_DEPRECATION_WARNINGS | ||
| 366 | 664 | dst->properties = src->properties; | |
| 367 | FF_ENABLE_DEPRECATION_WARNINGS | ||
| 368 | #endif | ||
| 369 | |||
| 370 | 664 | dst->bits_per_coded_sample = src->bits_per_coded_sample; | |
| 371 | 664 | dst->sample_aspect_ratio = src->sample_aspect_ratio; | |
| 372 | |||
| 373 | 664 | dst->profile = src->profile; | |
| 374 | 664 | dst->level = src->level; | |
| 375 | |||
| 376 | 664 | dst->bits_per_raw_sample = src->bits_per_raw_sample; | |
| 377 | 664 | dst->color_primaries = src->color_primaries; | |
| 378 | |||
| 379 | 664 | dst->color_trc = src->color_trc; | |
| 380 | 664 | dst->colorspace = src->colorspace; | |
| 381 | 664 | dst->color_range = src->color_range; | |
| 382 | 664 | dst->chroma_sample_location = src->chroma_sample_location; | |
| 383 | |||
| 384 | 664 | dst->sample_rate = src->sample_rate; | |
| 385 | 664 | dst->sample_fmt = src->sample_fmt; | |
| 386 | 664 | err = av_channel_layout_copy(&dst->ch_layout, &src->ch_layout); | |
| 387 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 664 times.
|
664 | if (err < 0) |
| 388 | ✗ | return err; | |
| 389 | |||
| 390 |
1/2✓ Branch 0 taken 664 times.
✗ Branch 1 not taken.
|
664 | if (!!dst->hw_frames_ctx != !!src->hw_frames_ctx || |
| 391 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 664 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
664 | (dst->hw_frames_ctx && dst->hw_frames_ctx->data != src->hw_frames_ctx->data)) { |
| 392 | ✗ | av_buffer_unref(&dst->hw_frames_ctx); | |
| 393 | |||
| 394 | ✗ | if (src->hw_frames_ctx) { | |
| 395 | ✗ | dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx); | |
| 396 | ✗ | if (!dst->hw_frames_ctx) | |
| 397 | ✗ | return AVERROR(ENOMEM); | |
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | 664 | dst->hwaccel_flags = src->hwaccel_flags; | |
| 402 | |||
| 403 | 664 | av_refstruct_replace(&dst->internal->pool, src->internal->pool); | |
| 404 | 664 | ff_decode_internal_sync(dst, src); | |
| 405 | } | ||
| 406 | |||
| 407 |
2/2✓ Branch 0 taken 556 times.
✓ Branch 1 taken 555 times.
|
1111 | if (for_user) { |
| 408 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 498 times.
|
556 | if (codec->update_thread_context_for_user) |
| 409 | 58 | err = codec->update_thread_context_for_user(dst, src); | |
| 410 | } else { | ||
| 411 | 555 | const PerThreadContext *p_src = src->internal->thread_ctx; | |
| 412 | 555 | PerThreadContext *p_dst = dst->internal->thread_ctx; | |
| 413 | |||
| 414 |
2/2✓ Branch 0 taken 108 times.
✓ Branch 1 taken 447 times.
|
555 | if (codec->update_thread_context) { |
| 415 | 108 | err = codec->update_thread_context(dst, src); | |
| 416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
|
108 | if (err < 0) |
| 417 | ✗ | return err; | |
| 418 | } | ||
| 419 | |||
| 420 | // reset dst hwaccel state if needed | ||
| 421 |
3/6✓ Branch 0 taken 555 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 555 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 555 times.
|
555 | av_assert0(p_dst->hwaccel_threadsafe || |
| 422 | (!dst->hwaccel && !dst->internal->hwaccel_priv_data)); | ||
| 423 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 555 times.
|
555 | if (p_dst->hwaccel_threadsafe && |
| 424 | ✗ | (!p_src->hwaccel_threadsafe || dst->hwaccel != src->hwaccel)) { | |
| 425 | ✗ | ff_hwaccel_uninit(dst); | |
| 426 | ✗ | p_dst->hwaccel_threadsafe = 0; | |
| 427 | } | ||
| 428 | |||
| 429 | // propagate hwaccel state for threadsafe hwaccels | ||
| 430 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 555 times.
|
555 | if (p_src->hwaccel_threadsafe) { |
| 431 | ✗ | const FFHWAccel *hwaccel = ffhwaccel(src->hwaccel); | |
| 432 | ✗ | if (!dst->hwaccel) { | |
| 433 | ✗ | if (hwaccel->priv_data_size) { | |
| 434 | ✗ | av_assert0(hwaccel->update_thread_context); | |
| 435 | |||
| 436 | ✗ | dst->internal->hwaccel_priv_data = | |
| 437 | ✗ | av_mallocz(hwaccel->priv_data_size); | |
| 438 | ✗ | if (!dst->internal->hwaccel_priv_data) | |
| 439 | ✗ | return AVERROR(ENOMEM); | |
| 440 | } | ||
| 441 | ✗ | dst->hwaccel = src->hwaccel; | |
| 442 | } | ||
| 443 | ✗ | av_assert0(dst->hwaccel == src->hwaccel); | |
| 444 | |||
| 445 | ✗ | if (hwaccel->update_thread_context) { | |
| 446 | ✗ | err = hwaccel->update_thread_context(dst, src); | |
| 447 | ✗ | if (err < 0) { | |
| 448 | ✗ | av_log(dst, AV_LOG_ERROR, "Error propagating hwaccel state\n"); | |
| 449 | ✗ | ff_hwaccel_uninit(dst); | |
| 450 | ✗ | return err; | |
| 451 | } | ||
| 452 | } | ||
| 453 | ✗ | p_dst->hwaccel_threadsafe = 1; | |
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | 1111 | return err; | |
| 458 | } | ||
| 459 | |||
| 460 | /** | ||
| 461 | * Update the next thread's AVCodecContext with values set by the user. | ||
| 462 | * | ||
| 463 | * @param dst The destination context. | ||
| 464 | * @param src The source context. | ||
| 465 | * @return 0 on success, negative error code on failure | ||
| 466 | */ | ||
| 467 | 606 | static int update_context_from_user(AVCodecContext *dst, const AVCodecContext *src) | |
| 468 | { | ||
| 469 | int err; | ||
| 470 | |||
| 471 | 606 | dst->flags = src->flags; | |
| 472 | |||
| 473 | 606 | dst->draw_horiz_band= src->draw_horiz_band; | |
| 474 | 606 | dst->get_buffer2 = src->get_buffer2; | |
| 475 | |||
| 476 | 606 | dst->opaque = src->opaque; | |
| 477 | 606 | dst->debug = src->debug; | |
| 478 | |||
| 479 | 606 | dst->slice_flags = src->slice_flags; | |
| 480 | 606 | dst->flags2 = src->flags2; | |
| 481 | 606 | dst->export_side_data = src->export_side_data; | |
| 482 | |||
| 483 | 606 | dst->skip_loop_filter = src->skip_loop_filter; | |
| 484 | 606 | dst->skip_idct = src->skip_idct; | |
| 485 | 606 | dst->skip_frame = src->skip_frame; | |
| 486 | |||
| 487 | 606 | dst->frame_num = src->frame_num; | |
| 488 | |||
| 489 | 606 | av_packet_unref(dst->internal->last_pkt_props); | |
| 490 | 606 | err = av_packet_copy_props(dst->internal->last_pkt_props, src->internal->last_pkt_props); | |
| 491 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
|
606 | if (err < 0) |
| 492 | ✗ | return err; | |
| 493 | |||
| 494 | 606 | return 0; | |
| 495 | } | ||
| 496 | |||
| 497 | 606 | static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx, | |
| 498 | AVPacket *in_pkt) | ||
| 499 | { | ||
| 500 | 606 | FrameThreadContext *fctx = p->parent; | |
| 501 | 606 | PerThreadContext *prev_thread = fctx->prev_thread; | |
| 502 | 606 | const AVCodec *codec = p->avctx->codec; | |
| 503 | int ret; | ||
| 504 | |||
| 505 | 606 | pthread_mutex_lock(&p->mutex); | |
| 506 | |||
| 507 | 606 | av_packet_unref(p->avpkt); | |
| 508 | 606 | av_packet_move_ref(p->avpkt, in_pkt); | |
| 509 | |||
| 510 |
3/4✓ Branch 0 taken 68 times.
✓ Branch 1 taken 538 times.
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
|
606 | if (AVPACKET_IS_EMPTY(p->avpkt)) |
| 511 | 68 | p->avctx->internal->draining = 1; | |
| 512 | |||
| 513 | 606 | ret = update_context_from_user(p->avctx, user_avctx); | |
| 514 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
|
606 | if (ret) { |
| 515 | ✗ | pthread_mutex_unlock(&p->mutex); | |
| 516 | ✗ | return ret; | |
| 517 | } | ||
| 518 | 606 | atomic_store_explicit(&p->debug_threads, | |
| 519 | (p->avctx->debug & FF_DEBUG_THREADS) != 0, | ||
| 520 | memory_order_relaxed); | ||
| 521 | |||
| 522 |
2/2✓ Branch 0 taken 596 times.
✓ Branch 1 taken 10 times.
|
606 | if (prev_thread) { |
| 523 |
2/2✓ Branch 0 taken 364 times.
✓ Branch 1 taken 232 times.
|
596 | if (atomic_load(&prev_thread->state) == STATE_SETTING_UP) { |
| 524 | 364 | pthread_mutex_lock(&prev_thread->progress_mutex); | |
| 525 |
2/2✓ Branch 0 taken 364 times.
✓ Branch 1 taken 364 times.
|
728 | while (atomic_load(&prev_thread->state) == STATE_SETTING_UP) |
| 526 | 364 | pthread_cond_wait(&prev_thread->progress_cond, &prev_thread->progress_mutex); | |
| 527 | 364 | pthread_mutex_unlock(&prev_thread->progress_mutex); | |
| 528 | } | ||
| 529 | |||
| 530 | /* codecs without delay might not be prepared to be called repeatedly here during | ||
| 531 | * flushing (vp3/theora), and also don't need to be, since from this point on, they | ||
| 532 | * will always return EOF anyway */ | ||
| 533 |
2/2✓ Branch 0 taken 68 times.
✓ Branch 1 taken 528 times.
|
596 | if (!p->avctx->internal->draining || |
| 534 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 41 times.
|
68 | (codec->capabilities & AV_CODEC_CAP_DELAY)) { |
| 535 | 555 | ret = update_context_from_thread(p->avctx, prev_thread->avctx, 0); | |
| 536 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 555 times.
|
555 | if (ret) { |
| 537 | ✗ | pthread_mutex_unlock(&p->mutex); | |
| 538 | ✗ | return ret; | |
| 539 | } | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | /* transfer the stashed hwaccel state, if any */ | ||
| 544 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
606 | av_assert0(!p->avctx->hwaccel || p->hwaccel_threadsafe); |
| 545 |
1/2✓ Branch 0 taken 606 times.
✗ Branch 1 not taken.
|
606 | if (!p->hwaccel_threadsafe) { |
| 546 | 606 | FFSWAP(const AVHWAccel*, p->avctx->hwaccel, fctx->stash_hwaccel); | |
| 547 | 606 | FFSWAP(void*, p->avctx->hwaccel_context, fctx->stash_hwaccel_context); | |
| 548 | 606 | FFSWAP(void*, p->avctx->internal->hwaccel_priv_data, fctx->stash_hwaccel_priv); | |
| 549 | } | ||
| 550 | |||
| 551 | 606 | atomic_store(&p->state, STATE_SETTING_UP); | |
| 552 | 606 | pthread_cond_signal(&p->input_cond); | |
| 553 | 606 | pthread_mutex_unlock(&p->mutex); | |
| 554 | |||
| 555 | 606 | fctx->prev_thread = p; | |
| 556 | 606 | fctx->next_decoding = (fctx->next_decoding + 1) % p->avctx->thread_count; | |
| 557 | |||
| 558 | 606 | return 0; | |
| 559 | } | ||
| 560 | |||
| 561 | 832 | int ff_thread_receive_frame(AVCodecContext *avctx, AVFrame *frame) | |
| 562 | { | ||
| 563 | 832 | FrameThreadContext *fctx = avctx->internal->thread_ctx; | |
| 564 | 832 | int ret = 0; | |
| 565 | |||
| 566 | /* release the async lock, permitting blocked hwaccel threads to | ||
| 567 | * go forward while we are in this function */ | ||
| 568 | 832 | async_unlock(fctx); | |
| 569 | |||
| 570 | /* submit packets to threads while there are no buffered results to return */ | ||
| 571 |
4/4✓ Branch 0 taken 901 times.
✓ Branch 1 taken 537 times.
✓ Branch 2 taken 892 times.
✓ Branch 3 taken 9 times.
|
1438 | while (!fctx->df.nb_f && !fctx->result) { |
| 572 | PerThreadContext *p; | ||
| 573 | |||
| 574 | /* get a packet to be submitted to the next thread */ | ||
| 575 | 892 | av_packet_unref(fctx->next_pkt); | |
| 576 | 892 | ret = ff_decode_get_packet(avctx, fctx->next_pkt); | |
| 577 |
4/4✓ Branch 0 taken 354 times.
✓ Branch 1 taken 538 times.
✓ Branch 2 taken 286 times.
✓ Branch 3 taken 68 times.
|
892 | if (ret < 0 && ret != AVERROR_EOF) |
| 578 | 286 | goto finish; | |
| 579 | |||
| 580 | 606 | ret = submit_packet(&fctx->threads[fctx->next_decoding], avctx, | |
| 581 | fctx->next_pkt); | ||
| 582 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
|
606 | if (ret < 0) |
| 583 | ✗ | goto finish; | |
| 584 | |||
| 585 | /* do not return any frames until all threads have something to do */ | ||
| 586 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 534 times.
|
606 | if (fctx->next_decoding != fctx->next_finished && |
| 587 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 12 times.
|
72 | !avctx->internal->draining) |
| 588 | 60 | continue; | |
| 589 | |||
| 590 | 546 | p = &fctx->threads[fctx->next_finished]; | |
| 591 | 546 | fctx->next_finished = (fctx->next_finished + 1) % avctx->thread_count; | |
| 592 | |||
| 593 |
2/2✓ Branch 0 taken 154 times.
✓ Branch 1 taken 392 times.
|
546 | if (atomic_load(&p->state) != STATE_INPUT_READY) { |
| 594 | 154 | pthread_mutex_lock(&p->progress_mutex); | |
| 595 |
2/2✓ Branch 0 taken 154 times.
✓ Branch 1 taken 154 times.
|
308 | while (atomic_load_explicit(&p->state, memory_order_relaxed) != STATE_INPUT_READY) |
| 596 | 154 | pthread_cond_wait(&p->output_cond, &p->progress_mutex); | |
| 597 | 154 | pthread_mutex_unlock(&p->progress_mutex); | |
| 598 | } | ||
| 599 | |||
| 600 | 546 | update_context_from_thread(avctx, p->avctx, 1); | |
| 601 | 546 | fctx->result = p->result; | |
| 602 | 546 | p->result = 0; | |
| 603 |
2/2✓ Branch 0 taken 535 times.
✓ Branch 1 taken 11 times.
|
546 | if (p->df.nb_f) |
| 604 | 535 | FFSWAP(DecodedFrames, fctx->df, p->df); | |
| 605 | } | ||
| 606 | |||
| 607 | /* a thread may return multiple frames AND an error | ||
| 608 | * we first return all the frames, then the error */ | ||
| 609 |
2/2✓ Branch 0 taken 537 times.
✓ Branch 1 taken 9 times.
|
546 | if (fctx->df.nb_f) { |
| 610 | 537 | decoded_frames_pop(&fctx->df, frame); | |
| 611 | 537 | ret = 0; | |
| 612 | } else { | ||
| 613 | 9 | ret = fctx->result; | |
| 614 | 9 | fctx->result = 0; | |
| 615 | } | ||
| 616 | |||
| 617 | 832 | finish: | |
| 618 | 832 | async_lock(fctx); | |
| 619 | 832 | return ret; | |
| 620 | } | ||
| 621 | |||
| 622 | 287199 | void ff_thread_report_progress(ThreadFrame *f, int n, int field) | |
| 623 | { | ||
| 624 | PerThreadContext *p; | ||
| 625 |
2/2✓ Branch 0 taken 1240 times.
✓ Branch 1 taken 285959 times.
|
287199 | atomic_int *progress = f->progress ? f->progress->progress : NULL; |
| 626 | |||
| 627 |
2/2✓ Branch 0 taken 1240 times.
✓ Branch 1 taken 285959 times.
|
287199 | if (!progress || |
| 628 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 1213 times.
|
1240 | atomic_load_explicit(&progress[field], memory_order_relaxed) >= n) |
| 629 | 285986 | return; | |
| 630 | |||
| 631 | 1213 | p = f->owner[field]->internal->thread_ctx; | |
| 632 | |||
| 633 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1213 times.
|
1213 | if (atomic_load_explicit(&p->debug_threads, memory_order_relaxed)) |
| 634 | ✗ | av_log(f->owner[field], AV_LOG_DEBUG, | |
| 635 | "%p finished %d field %d\n", progress, n, field); | ||
| 636 | |||
| 637 | 1213 | pthread_mutex_lock(&p->progress_mutex); | |
| 638 | |||
| 639 | 1213 | atomic_store_explicit(&progress[field], n, memory_order_release); | |
| 640 | |||
| 641 | 1213 | pthread_cond_broadcast(&p->progress_cond); | |
| 642 | 1213 | pthread_mutex_unlock(&p->progress_mutex); | |
| 643 | } | ||
| 644 | |||
| 645 | 150874 | void ff_thread_await_progress(const ThreadFrame *f, int n, int field) | |
| 646 | { | ||
| 647 | PerThreadContext *p; | ||
| 648 |
2/2✓ Branch 0 taken 150193 times.
✓ Branch 1 taken 681 times.
|
150874 | atomic_int *progress = f->progress ? f->progress->progress : NULL; |
| 649 | |||
| 650 |
2/2✓ Branch 0 taken 150193 times.
✓ Branch 1 taken 681 times.
|
150874 | if (!progress || |
| 651 |
2/2✓ Branch 0 taken 149716 times.
✓ Branch 1 taken 477 times.
|
150193 | atomic_load_explicit(&progress[field], memory_order_acquire) >= n) |
| 652 | 150397 | return; | |
| 653 | |||
| 654 | 477 | p = f->owner[field]->internal->thread_ctx; | |
| 655 | |||
| 656 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 477 times.
|
477 | if (atomic_load_explicit(&p->debug_threads, memory_order_relaxed)) |
| 657 | ✗ | av_log(f->owner[field], AV_LOG_DEBUG, | |
| 658 | "thread awaiting %d field %d from %p\n", n, field, progress); | ||
| 659 | |||
| 660 | 477 | pthread_mutex_lock(&p->progress_mutex); | |
| 661 |
2/2✓ Branch 0 taken 481 times.
✓ Branch 1 taken 477 times.
|
958 | while (atomic_load_explicit(&progress[field], memory_order_relaxed) < n) |
| 662 | 481 | pthread_cond_wait(&p->progress_cond, &p->progress_mutex); | |
| 663 | 477 | pthread_mutex_unlock(&p->progress_mutex); | |
| 664 | } | ||
| 665 | |||
| 666 | 24011 | void ff_thread_finish_setup(AVCodecContext *avctx) { | |
| 667 | PerThreadContext *p; | ||
| 668 | |||
| 669 |
2/2✓ Branch 0 taken 23405 times.
✓ Branch 1 taken 606 times.
|
24011 | if (!(avctx->active_thread_type&FF_THREAD_FRAME)) return; |
| 670 | |||
| 671 | 606 | p = avctx->internal->thread_ctx; | |
| 672 | |||
| 673 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
|
606 | p->hwaccel_threadsafe = avctx->hwaccel && |
| 674 | ✗ | (ffhwaccel(avctx->hwaccel)->caps_internal & HWACCEL_CAP_THREAD_SAFE); | |
| 675 | |||
| 676 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 606 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
606 | if (hwaccel_serial(avctx) && !p->hwaccel_serializing) { |
| 677 | ✗ | pthread_mutex_lock(&p->parent->hwaccel_mutex); | |
| 678 | ✗ | p->hwaccel_serializing = 1; | |
| 679 | } | ||
| 680 | |||
| 681 | /* this assumes that no hwaccel calls happen before ff_thread_finish_setup() */ | ||
| 682 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
|
606 | if (avctx->hwaccel && |
| 683 | ✗ | !(ffhwaccel(avctx->hwaccel)->caps_internal & HWACCEL_CAP_ASYNC_SAFE)) { | |
| 684 | ✗ | p->async_serializing = 1; | |
| 685 | |||
| 686 | ✗ | async_lock(p->parent); | |
| 687 | } | ||
| 688 | |||
| 689 | /* thread-unsafe hwaccels share a single private data instance, so we | ||
| 690 | * save hwaccel state for passing to the next thread; | ||
| 691 | * this is done here so that this worker thread can wipe its own hwaccel | ||
| 692 | * state after decoding, without requiring synchronization */ | ||
| 693 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
|
606 | av_assert0(!p->parent->stash_hwaccel); |
| 694 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 606 times.
|
606 | if (hwaccel_serial(avctx)) { |
| 695 | ✗ | p->parent->stash_hwaccel = avctx->hwaccel; | |
| 696 | ✗ | p->parent->stash_hwaccel_context = avctx->hwaccel_context; | |
| 697 | ✗ | p->parent->stash_hwaccel_priv = avctx->internal->hwaccel_priv_data; | |
| 698 | } | ||
| 699 | |||
| 700 | 606 | pthread_mutex_lock(&p->progress_mutex); | |
| 701 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
|
606 | if(atomic_load(&p->state) == STATE_SETUP_FINISHED){ |
| 702 | ✗ | av_log(avctx, AV_LOG_WARNING, "Multiple ff_thread_finish_setup() calls\n"); | |
| 703 | } | ||
| 704 | |||
| 705 | 606 | atomic_store(&p->state, STATE_SETUP_FINISHED); | |
| 706 | |||
| 707 | 606 | pthread_cond_broadcast(&p->progress_cond); | |
| 708 | 606 | pthread_mutex_unlock(&p->progress_mutex); | |
| 709 | } | ||
| 710 | |||
| 711 | /// Waits for all threads to finish. | ||
| 712 | 10 | static av_cold void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count) | |
| 713 | { | ||
| 714 | int i; | ||
| 715 | |||
| 716 | 10 | async_unlock(fctx); | |
| 717 | |||
| 718 |
2/2✓ Branch 0 taken 76 times.
✓ Branch 1 taken 10 times.
|
86 | for (i = 0; i < thread_count; i++) { |
| 719 | 76 | PerThreadContext *p = &fctx->threads[i]; | |
| 720 | |||
| 721 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 70 times.
|
76 | if (atomic_load(&p->state) != STATE_INPUT_READY) { |
| 722 | 6 | pthread_mutex_lock(&p->progress_mutex); | |
| 723 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | while (atomic_load(&p->state) != STATE_INPUT_READY) |
| 724 | 6 | pthread_cond_wait(&p->output_cond, &p->progress_mutex); | |
| 725 | 6 | pthread_mutex_unlock(&p->progress_mutex); | |
| 726 | } | ||
| 727 | } | ||
| 728 | |||
| 729 | 10 | async_lock(fctx); | |
| 730 | 10 | } | |
| 731 | |||
| 732 | #define OFF(member) offsetof(FrameThreadContext, member) | ||
| 733 | DEFINE_OFFSET_ARRAY(FrameThreadContext, thread_ctx, pthread_init_cnt, | ||
| 734 | (OFF(buffer_mutex), OFF(hwaccel_mutex), OFF(async_mutex)), | ||
| 735 | (OFF(async_cond))); | ||
| 736 | #undef OFF | ||
| 737 | |||
| 738 | #define OFF(member) offsetof(PerThreadContext, member) | ||
| 739 | DEFINE_OFFSET_ARRAY(PerThreadContext, per_thread, pthread_init_cnt, | ||
| 740 | (OFF(progress_mutex), OFF(mutex)), | ||
| 741 | (OFF(input_cond), OFF(progress_cond), OFF(output_cond))); | ||
| 742 | #undef OFF | ||
| 743 | |||
| 744 | 10 | av_cold void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) | |
| 745 | { | ||
| 746 | 10 | FrameThreadContext *fctx = avctx->internal->thread_ctx; | |
| 747 | 10 | const FFCodec *codec = ffcodec(avctx->codec); | |
| 748 | int i; | ||
| 749 | |||
| 750 | 10 | park_frame_worker_threads(fctx, thread_count); | |
| 751 | |||
| 752 |
2/2✓ Branch 0 taken 76 times.
✓ Branch 1 taken 10 times.
|
86 | for (i = 0; i < thread_count; i++) { |
| 753 | 76 | PerThreadContext *p = &fctx->threads[i]; | |
| 754 | 76 | AVCodecContext *ctx = p->avctx; | |
| 755 | |||
| 756 |
1/2✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
|
76 | if (ctx->internal) { |
| 757 |
1/2✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
|
76 | if (p->thread_init == INITIALIZED) { |
| 758 | 76 | pthread_mutex_lock(&p->mutex); | |
| 759 | 76 | p->die = 1; | |
| 760 | 76 | pthread_cond_signal(&p->input_cond); | |
| 761 | 76 | pthread_mutex_unlock(&p->mutex); | |
| 762 | |||
| 763 | 76 | pthread_join(p->thread, NULL); | |
| 764 | } | ||
| 765 |
2/4✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
|
76 | if (codec->close && p->thread_init != UNINITIALIZED) |
| 766 | 76 | codec->close(ctx); | |
| 767 | |||
| 768 | /* When using a threadsafe hwaccel, this is where | ||
| 769 | * each thread's context is uninit'd and freed. */ | ||
| 770 | 76 | ff_hwaccel_uninit(ctx); | |
| 771 | |||
| 772 |
1/2✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
|
76 | if (ctx->priv_data) { |
| 773 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 18 times.
|
76 | if (codec->p.priv_class) |
| 774 | 58 | av_opt_free(ctx->priv_data); | |
| 775 | 76 | av_freep(&ctx->priv_data); | |
| 776 | } | ||
| 777 | |||
| 778 | 76 | av_refstruct_unref(&ctx->internal->pool); | |
| 779 | 76 | av_packet_free(&ctx->internal->in_pkt); | |
| 780 | 76 | av_packet_free(&ctx->internal->last_pkt_props); | |
| 781 | 76 | ff_decode_internal_uninit(ctx); | |
| 782 | 76 | av_freep(&ctx->internal); | |
| 783 | 76 | av_buffer_unref(&ctx->hw_frames_ctx); | |
| 784 | 76 | av_frame_side_data_free(&ctx->decoded_side_data, | |
| 785 | &ctx->nb_decoded_side_data); | ||
| 786 | } | ||
| 787 | |||
| 788 | 76 | decoded_frames_free(&p->df); | |
| 789 | |||
| 790 | 76 | ff_pthread_free(p, per_thread_offsets); | |
| 791 | 76 | av_packet_free(&p->avpkt); | |
| 792 | |||
| 793 | 76 | av_freep(&p->avctx); | |
| 794 | } | ||
| 795 | |||
| 796 | 10 | decoded_frames_free(&fctx->df); | |
| 797 | 10 | av_packet_free(&fctx->next_pkt); | |
| 798 | |||
| 799 | 10 | av_freep(&fctx->threads); | |
| 800 | 10 | ff_pthread_free(fctx, thread_ctx_offsets); | |
| 801 | |||
| 802 | /* if we have stashed hwaccel state, move it to the user-facing context, | ||
| 803 | * so it will be freed in ff_codec_close() */ | ||
| 804 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | av_assert0(!avctx->hwaccel); |
| 805 | 10 | FFSWAP(const AVHWAccel*, avctx->hwaccel, fctx->stash_hwaccel); | |
| 806 | 10 | FFSWAP(void*, avctx->hwaccel_context, fctx->stash_hwaccel_context); | |
| 807 | 10 | FFSWAP(void*, avctx->internal->hwaccel_priv_data, fctx->stash_hwaccel_priv); | |
| 808 | |||
| 809 | 10 | av_freep(&avctx->internal->thread_ctx); | |
| 810 | 10 | } | |
| 811 | |||
| 812 | 76 | static av_cold int init_thread(PerThreadContext *p, int *threads_to_free, | |
| 813 | FrameThreadContext *fctx, AVCodecContext *avctx, | ||
| 814 | const FFCodec *codec, int first) | ||
| 815 | { | ||
| 816 | AVCodecContext *copy; | ||
| 817 | int err; | ||
| 818 | |||
| 819 | 76 | atomic_init(&p->state, STATE_INPUT_READY); | |
| 820 | |||
| 821 | 76 | copy = av_memdup(avctx, sizeof(*avctx)); | |
| 822 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
|
76 | if (!copy) |
| 823 | ✗ | return AVERROR(ENOMEM); | |
| 824 | 76 | copy->priv_data = NULL; | |
| 825 | 76 | copy->decoded_side_data = NULL; | |
| 826 | 76 | copy->nb_decoded_side_data = 0; | |
| 827 | |||
| 828 | /* From now on, this PerThreadContext will be cleaned up by | ||
| 829 | * ff_frame_thread_free in case of errors. */ | ||
| 830 | 76 | (*threads_to_free)++; | |
| 831 | |||
| 832 | 76 | p->parent = fctx; | |
| 833 | 76 | p->avctx = copy; | |
| 834 | |||
| 835 | 76 | copy->internal = ff_decode_internal_alloc(); | |
| 836 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
|
76 | if (!copy->internal) |
| 837 | ✗ | return AVERROR(ENOMEM); | |
| 838 | 76 | ff_decode_internal_sync(copy, avctx); | |
| 839 | 76 | copy->internal->thread_ctx = p; | |
| 840 | 76 | copy->internal->progress_frame_pool = avctx->internal->progress_frame_pool; | |
| 841 | |||
| 842 | 76 | copy->delay = avctx->delay; | |
| 843 | |||
| 844 |
1/2✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
|
76 | if (codec->priv_data_size) { |
| 845 | 76 | copy->priv_data = av_mallocz(codec->priv_data_size); | |
| 846 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
|
76 | if (!copy->priv_data) |
| 847 | ✗ | return AVERROR(ENOMEM); | |
| 848 | |||
| 849 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 18 times.
|
76 | if (codec->p.priv_class) { |
| 850 | 58 | *(const AVClass **)copy->priv_data = codec->p.priv_class; | |
| 851 | 58 | err = av_opt_copy(copy->priv_data, avctx->priv_data); | |
| 852 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
|
58 | if (err < 0) |
| 853 | ✗ | return err; | |
| 854 | } | ||
| 855 | } | ||
| 856 | |||
| 857 | 76 | err = ff_pthread_init(p, per_thread_offsets); | |
| 858 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
|
76 | if (err < 0) |
| 859 | ✗ | return err; | |
| 860 | |||
| 861 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 76 times.
|
76 | if (!(p->avpkt = av_packet_alloc())) |
| 862 | ✗ | return AVERROR(ENOMEM); | |
| 863 | |||
| 864 | 76 | copy->internal->is_frame_mt = 1; | |
| 865 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 10 times.
|
76 | if (!first) |
| 866 | 66 | copy->internal->is_copy = 1; | |
| 867 | |||
| 868 | 76 | copy->internal->in_pkt = av_packet_alloc(); | |
| 869 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
|
76 | if (!copy->internal->in_pkt) |
| 870 | ✗ | return AVERROR(ENOMEM); | |
| 871 | |||
| 872 | 76 | copy->internal->last_pkt_props = av_packet_alloc(); | |
| 873 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
|
76 | if (!copy->internal->last_pkt_props) |
| 874 | ✗ | return AVERROR(ENOMEM); | |
| 875 | |||
| 876 |
1/2✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
|
76 | if (codec->init) { |
| 877 | 76 | err = codec->init(copy); | |
| 878 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
|
76 | if (err < 0) { |
| 879 | ✗ | if (codec->caps_internal & FF_CODEC_CAP_INIT_CLEANUP) | |
| 880 | ✗ | p->thread_init = NEEDS_CLOSE; | |
| 881 | ✗ | return err; | |
| 882 | } | ||
| 883 | } | ||
| 884 | 76 | p->thread_init = NEEDS_CLOSE; | |
| 885 | |||
| 886 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 66 times.
|
76 | if (first) { |
| 887 | 10 | update_context_from_thread(avctx, copy, 1); | |
| 888 | |||
| 889 | 10 | av_frame_side_data_free(&avctx->decoded_side_data, &avctx->nb_decoded_side_data); | |
| 890 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | for (int i = 0; i < copy->nb_decoded_side_data; i++) { |
| 891 | ✗ | err = av_frame_side_data_clone(&avctx->decoded_side_data, | |
| 892 | &avctx->nb_decoded_side_data, | ||
| 893 | ✗ | copy->decoded_side_data[i], 0); | |
| 894 | ✗ | if (err < 0) | |
| 895 | ✗ | return err; | |
| 896 | } | ||
| 897 | } | ||
| 898 | |||
| 899 | 76 | atomic_init(&p->debug_threads, (copy->debug & FF_DEBUG_THREADS) != 0); | |
| 900 | |||
| 901 | 76 | err = AVERROR(pthread_create(&p->thread, NULL, frame_worker_thread, p)); | |
| 902 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
|
76 | if (err < 0) |
| 903 | ✗ | return err; | |
| 904 | 76 | p->thread_init = INITIALIZED; | |
| 905 | |||
| 906 | 76 | return 0; | |
| 907 | } | ||
| 908 | |||
| 909 | 10 | av_cold int ff_frame_thread_init(AVCodecContext *avctx) | |
| 910 | { | ||
| 911 | 10 | int thread_count = avctx->thread_count; | |
| 912 | 10 | const FFCodec *codec = ffcodec(avctx->codec); | |
| 913 | FrameThreadContext *fctx; | ||
| 914 | 10 | int err, i = 0; | |
| 915 | |||
| 916 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (!thread_count) { |
| 917 | ✗ | int nb_cpus = av_cpu_count(); | |
| 918 | // use number of cores + 1 as thread count if there is more than one | ||
| 919 | ✗ | if (nb_cpus > 1) | |
| 920 | ✗ | thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS); | |
| 921 | else | ||
| 922 | ✗ | thread_count = avctx->thread_count = 1; | |
| 923 | } | ||
| 924 | |||
| 925 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (thread_count <= 1) { |
| 926 | ✗ | avctx->active_thread_type = 0; | |
| 927 | ✗ | return 0; | |
| 928 | } | ||
| 929 | |||
| 930 | 10 | avctx->internal->thread_ctx = fctx = av_mallocz(sizeof(FrameThreadContext)); | |
| 931 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (!fctx) |
| 932 | ✗ | return AVERROR(ENOMEM); | |
| 933 | |||
| 934 | 10 | err = ff_pthread_init(fctx, thread_ctx_offsets); | |
| 935 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (err < 0) { |
| 936 | ✗ | ff_pthread_free(fctx, thread_ctx_offsets); | |
| 937 | ✗ | av_freep(&avctx->internal->thread_ctx); | |
| 938 | ✗ | return err; | |
| 939 | } | ||
| 940 | |||
| 941 | 10 | fctx->next_pkt = av_packet_alloc(); | |
| 942 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (!fctx->next_pkt) |
| 943 | ✗ | return AVERROR(ENOMEM); | |
| 944 | |||
| 945 | 10 | fctx->async_lock = 1; | |
| 946 | |||
| 947 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
|
10 | if (codec->p.type == AVMEDIA_TYPE_VIDEO) |
| 948 | 6 | avctx->delay = avctx->thread_count - 1; | |
| 949 | |||
| 950 | 10 | fctx->threads = av_calloc(thread_count, sizeof(*fctx->threads)); | |
| 951 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (!fctx->threads) { |
| 952 | ✗ | err = AVERROR(ENOMEM); | |
| 953 | ✗ | goto error; | |
| 954 | } | ||
| 955 | |||
| 956 |
2/2✓ Branch 0 taken 76 times.
✓ Branch 1 taken 10 times.
|
86 | for (; i < thread_count; ) { |
| 957 | 76 | PerThreadContext *p = &fctx->threads[i]; | |
| 958 | 76 | int first = !i; | |
| 959 | |||
| 960 | 76 | err = init_thread(p, &i, fctx, avctx, codec, first); | |
| 961 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
|
76 | if (err < 0) |
| 962 | ✗ | goto error; | |
| 963 | } | ||
| 964 | |||
| 965 | 10 | return 0; | |
| 966 | |||
| 967 | ✗ | error: | |
| 968 | ✗ | ff_frame_thread_free(avctx, i); | |
| 969 | ✗ | return err; | |
| 970 | } | ||
| 971 | |||
| 972 | ✗ | av_cold void ff_thread_flush(AVCodecContext *avctx) | |
| 973 | { | ||
| 974 | int i; | ||
| 975 | ✗ | FrameThreadContext *fctx = avctx->internal->thread_ctx; | |
| 976 | |||
| 977 | ✗ | if (!fctx) return; | |
| 978 | |||
| 979 | ✗ | park_frame_worker_threads(fctx, avctx->thread_count); | |
| 980 | ✗ | if (fctx->prev_thread) { | |
| 981 | ✗ | if (fctx->prev_thread != &fctx->threads[0]) | |
| 982 | ✗ | update_context_from_thread(fctx->threads[0].avctx, fctx->prev_thread->avctx, 0); | |
| 983 | } | ||
| 984 | |||
| 985 | ✗ | fctx->next_decoding = fctx->next_finished = 0; | |
| 986 | ✗ | fctx->prev_thread = NULL; | |
| 987 | |||
| 988 | ✗ | decoded_frames_flush(&fctx->df); | |
| 989 | ✗ | fctx->result = 0; | |
| 990 | |||
| 991 | ✗ | for (i = 0; i < avctx->thread_count; i++) { | |
| 992 | ✗ | PerThreadContext *p = &fctx->threads[i]; | |
| 993 | |||
| 994 | ✗ | decoded_frames_flush(&p->df); | |
| 995 | ✗ | p->result = 0; | |
| 996 | |||
| 997 | ✗ | avcodec_flush_buffers(p->avctx); | |
| 998 | } | ||
| 999 | } | ||
| 1000 | |||
| 1001 | 37100 | int ff_thread_can_start_frame(AVCodecContext *avctx) | |
| 1002 | { | ||
| 1003 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 37048 times.
|
37100 | if ((avctx->active_thread_type & FF_THREAD_FRAME) && |
| 1004 |
1/2✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
|
52 | ffcodec(avctx->codec)->update_thread_context) { |
| 1005 | 52 | PerThreadContext *p = avctx->internal->thread_ctx; | |
| 1006 | |||
| 1007 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (atomic_load(&p->state) != STATE_SETTING_UP) |
| 1008 | ✗ | return 0; | |
| 1009 | } | ||
| 1010 | |||
| 1011 | 37100 | return 1; | |
| 1012 | } | ||
| 1013 | |||
| 1014 | 52962 | static int thread_get_buffer_internal(AVCodecContext *avctx, AVFrame *f, int flags) | |
| 1015 | { | ||
| 1016 | PerThreadContext *p; | ||
| 1017 | int err; | ||
| 1018 | |||
| 1019 |
2/2✓ Branch 0 taken 52424 times.
✓ Branch 1 taken 538 times.
|
52962 | if (!(avctx->active_thread_type & FF_THREAD_FRAME)) |
| 1020 | 52424 | return ff_get_buffer(avctx, f, flags); | |
| 1021 | |||
| 1022 | 538 | p = avctx->internal->thread_ctx; | |
| 1023 |
2/2✓ Branch 0 taken 453 times.
✓ Branch 1 taken 85 times.
|
538 | if (atomic_load(&p->state) != STATE_SETTING_UP && |
| 1024 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 453 times.
|
453 | ffcodec(avctx->codec)->update_thread_context) { |
| 1025 | ✗ | av_log(avctx, AV_LOG_ERROR, "get_buffer() cannot be called after ff_thread_finish_setup()\n"); | |
| 1026 | ✗ | return -1; | |
| 1027 | } | ||
| 1028 | |||
| 1029 | 538 | pthread_mutex_lock(&p->parent->buffer_mutex); | |
| 1030 | 538 | err = ff_get_buffer(avctx, f, flags); | |
| 1031 | |||
| 1032 | 538 | pthread_mutex_unlock(&p->parent->buffer_mutex); | |
| 1033 | |||
| 1034 | 538 | return err; | |
| 1035 | } | ||
| 1036 | |||
| 1037 | 52962 | int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f, int flags) | |
| 1038 | { | ||
| 1039 | 52962 | int ret = thread_get_buffer_internal(avctx, f, flags); | |
| 1040 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52962 times.
|
52962 | if (ret < 0) |
| 1041 | ✗ | av_log(avctx, AV_LOG_ERROR, "thread_get_buffer() failed\n"); | |
| 1042 | 52962 | return ret; | |
| 1043 | } | ||
| 1044 | |||
| 1045 | 25683 | int ff_thread_get_ext_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) | |
| 1046 | { | ||
| 1047 | int ret; | ||
| 1048 | |||
| 1049 | 25683 | f->owner[0] = f->owner[1] = avctx; | |
| 1050 |
2/2✓ Branch 0 taken 25641 times.
✓ Branch 1 taken 42 times.
|
25683 | if (!(avctx->active_thread_type & FF_THREAD_FRAME)) |
| 1051 | 25641 | return ff_get_buffer(avctx, f->f, flags); | |
| 1052 | |||
| 1053 | 42 | f->progress = av_refstruct_allocz(sizeof(*f->progress)); | |
| 1054 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (!f->progress) |
| 1055 | ✗ | return AVERROR(ENOMEM); | |
| 1056 | |||
| 1057 | 42 | atomic_init(&f->progress->progress[0], -1); | |
| 1058 | 42 | atomic_init(&f->progress->progress[1], -1); | |
| 1059 | |||
| 1060 | 42 | ret = ff_thread_get_buffer(avctx, f->f, flags); | |
| 1061 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (ret) |
| 1062 | ✗ | av_refstruct_unref(&f->progress); | |
| 1063 | 42 | return ret; | |
| 1064 | } | ||
| 1065 | |||
| 1066 | 53250 | void ff_thread_release_ext_buffer(ThreadFrame *f) | |
| 1067 | { | ||
| 1068 | 53250 | av_refstruct_unref(&f->progress); | |
| 1069 | 53250 | f->owner[0] = f->owner[1] = NULL; | |
| 1070 |
1/2✓ Branch 0 taken 53250 times.
✗ Branch 1 not taken.
|
53250 | if (f->f) |
| 1071 | 53250 | av_frame_unref(f->f); | |
| 1072 | 53250 | } | |
| 1073 | |||
| 1074 | 710 | av_cold enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset) | |
| 1075 | { | ||
| 1076 | PerThreadContext *p; | ||
| 1077 | const void *ref; | ||
| 1078 | |||
| 1079 |
2/2✓ Branch 0 taken 702 times.
✓ Branch 1 taken 8 times.
|
710 | if (!avctx->internal->is_copy) |
| 1080 | 702 | return avctx->active_thread_type & FF_THREAD_FRAME ? | |
| 1081 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 701 times.
|
702 | FF_THREAD_IS_FIRST_THREAD : FF_THREAD_NO_FRAME_THREADING; |
| 1082 | |||
| 1083 | 8 | p = avctx->internal->thread_ctx; | |
| 1084 | |||
| 1085 | av_assert1(memcpy(&ref, (char*)avctx->priv_data + offset, sizeof(ref)) && ref == NULL); | ||
| 1086 | |||
| 1087 | 8 | memcpy(&ref, (const char*)p->parent->threads[0].avctx->priv_data + offset, sizeof(ref)); | |
| 1088 | av_assert1(ref); | ||
| 1089 | 8 | av_refstruct_replace((char*)avctx->priv_data + offset, ref); | |
| 1090 | |||
| 1091 | 8 | return FF_THREAD_IS_COPY; | |
| 1092 | } | ||
| 1093 | |||
| 1094 | 1076 | int ff_thread_get_packet(AVCodecContext *avctx, AVPacket *pkt) | |
| 1095 | { | ||
| 1096 | 1076 | PerThreadContext *p = avctx->internal->thread_ctx; | |
| 1097 | |||
| 1098 |
3/4✓ Branch 0 taken 538 times.
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 538 times.
|
1076 | if (!AVPACKET_IS_EMPTY(p->avpkt)) { |
| 1099 | 538 | av_packet_move_ref(pkt, p->avpkt); | |
| 1100 | 538 | return 0; | |
| 1101 | } | ||
| 1102 | |||
| 1103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 538 times.
|
538 | return avctx->internal->draining ? AVERROR_EOF : AVERROR(EAGAIN); |
| 1104 | } | ||
| 1105 |