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