| File: | root/firefox-clang/media/ffvpx/libavcodec/pthread_frame.c |
| Warning: | line 435, 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_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 | static int hwaccel_serial(const AVCodecContext *avctx) | ||||
| 158 | { | ||||
| 159 | return avctx->hwaccel && !(ffhwaccel(avctx->hwaccel)->caps_internal & HWACCEL_CAP_THREAD_SAFE(1 << 1)); | ||||
| 160 | } | ||||
| 161 | |||||
| 162 | static void async_lock(FrameThreadContext *fctx) | ||||
| 163 | { | ||||
| 164 | pthread_mutex_lockstrict_pthread_mutex_lock(&fctx->async_mutex); | ||||
| 165 | while (fctx->async_lock) | ||||
| 166 | pthread_cond_waitstrict_pthread_cond_wait(&fctx->async_cond, &fctx->async_mutex); | ||||
| 167 | fctx->async_lock = 1; | ||||
| 168 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&fctx->async_mutex); | ||||
| 169 | } | ||||
| 170 | |||||
| 171 | static void async_unlock(FrameThreadContext *fctx) | ||||
| 172 | { | ||||
| 173 | pthread_mutex_lockstrict_pthread_mutex_lock(&fctx->async_mutex); | ||||
| 174 | 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" , 174); abort(); } } while (0); | ||||
| 175 | fctx->async_lock = 0; | ||||
| 176 | pthread_cond_broadcaststrict_pthread_cond_broadcast(&fctx->async_cond); | ||||
| 177 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&fctx->async_mutex); | ||||
| 178 | } | ||||
| 179 | |||||
| 180 | static void thread_set_name(PerThreadContext *p) | ||||
| 181 | { | ||||
| 182 | AVCodecContext *avctx = p->avctx; | ||||
| 183 | int idx = p - p->parent->threads; | ||||
| 184 | char name[16]; | ||||
| 185 | |||||
| 186 | snprintf(name, sizeof(name), "av:%.7s:df%d", avctx->codec->name, idx); | ||||
| 187 | |||||
| 188 | ff_thread_setname(name); | ||||
| 189 | } | ||||
| 190 | |||||
| 191 | // get a free frame to decode into | ||||
| 192 | static AVFrame *decoded_frames_get_free(DecodedFrames *df) | ||||
| 193 | { | ||||
| 194 | if (df->nb_f == df->nb_f_allocated) { | ||||
| 195 | AVFrame **tmp = av_realloc_array(df->f, df->nb_f + 1, | ||||
| 196 | sizeof(*df->f)); | ||||
| 197 | if (!tmp) | ||||
| 198 | return NULL((void*)0); | ||||
| 199 | df->f = tmp; | ||||
| 200 | |||||
| 201 | df->f[df->nb_f] = av_frame_alloc(); | ||||
| 202 | if (!df->f[df->nb_f]) | ||||
| 203 | return NULL((void*)0); | ||||
| 204 | |||||
| 205 | df->nb_f_allocated++; | ||||
| 206 | } | ||||
| 207 | |||||
| 208 | 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" , 208); abort(); } } while (0); | ||||
| 209 | |||||
| 210 | return df->f[df->nb_f]; | ||||
| 211 | } | ||||
| 212 | |||||
| 213 | static void decoded_frames_pop(DecodedFrames *df, AVFrame *dst) | ||||
| 214 | { | ||||
| 215 | AVFrame *tmp_frame = df->f[0]; | ||||
| 216 | av_frame_move_ref(dst, tmp_frame); | ||||
| 217 | memmove(df->f, df->f + 1, (df->nb_f - 1) * sizeof(*df->f)); | ||||
| 218 | df->f[--df->nb_f] = tmp_frame; | ||||
| 219 | } | ||||
| 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 | static void decoded_frames_free(DecodedFrames *df) | ||||
| 229 | { | ||||
| 230 | for (size_t i = 0; i < df->nb_f_allocated; i++) | ||||
| 231 | av_frame_free(&df->f[i]); | ||||
| 232 | av_freep(&df->f); | ||||
| 233 | df->nb_f = 0; | ||||
| 234 | df->nb_f_allocated = 0; | ||||
| 235 | } | ||||
| 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 | static attribute_align_arg void *frame_worker_thread(void *arg) | ||||
| 245 | { | ||||
| 246 | PerThreadContext *p = arg; | ||||
| 247 | AVCodecContext *avctx = p->avctx; | ||||
| 248 | const FFCodec *codec = ffcodec(avctx->codec); | ||||
| 249 | |||||
| 250 | thread_set_name(p); | ||||
| 251 | |||||
| 252 | pthread_mutex_lockstrict_pthread_mutex_lock(&p->mutex); | ||||
| 253 | while (1) { | ||||
| 254 | int ret; | ||||
| 255 | |||||
| 256 | while (atomic_load(&p->state)__c11_atomic_load(&p->state, 5) == STATE_INPUT_READY && !p->die) | ||||
| 257 | pthread_cond_waitstrict_pthread_cond_wait(&p->input_cond, &p->mutex); | ||||
| 258 | |||||
| 259 | if (p->die) break; | ||||
| 260 | |||||
| 261 | if (!codec->update_thread_context) | ||||
| 262 | 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 | 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" , 270); abort(); } } while (0); | ||||
| 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 | if (hwaccel_serial(avctx)) { | ||||
| 275 | pthread_mutex_lockstrict_pthread_mutex_lock(&p->parent->hwaccel_mutex); | ||||
| 276 | p->hwaccel_serializing = 1; | ||||
| 277 | } | ||||
| 278 | |||||
| 279 | ret = 0; | ||||
| 280 | while (ret >= 0) { | ||||
| 281 | AVFrame *frame; | ||||
| 282 | |||||
| 283 | /* get the frame which will store the output */ | ||||
| 284 | frame = decoded_frames_get_free(&p->df); | ||||
| 285 | if (!frame) { | ||||
| 286 | p->result = AVERROR(ENOMEM)(-(12)); | ||||
| 287 | goto alloc_fail; | ||||
| 288 | } | ||||
| 289 | |||||
| 290 | /* do the actual decoding */ | ||||
| 291 | ret = ff_decode_receive_frame_internal(avctx, frame); | ||||
| 292 | if (ret == 0) | ||||
| 293 | p->df.nb_f++; | ||||
| 294 | else if (ret < 0 && frame->buf[0]) | ||||
| 295 | av_frame_unref(frame); | ||||
| 296 | |||||
| 297 | p->result = (ret == AVERROR(EAGAIN)(-(11))) ? 0 : ret; | ||||
| 298 | } | ||||
| 299 | |||||
| 300 | if (atomic_load(&p->state)__c11_atomic_load(&p->state, 5) == STATE_SETTING_UP) | ||||
| 301 | ff_thread_finish_setup(avctx); | ||||
| 302 | |||||
| 303 | alloc_fail: | ||||
| 304 | 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((void*)0); | ||||
| 310 | avctx->hwaccel_context = NULL((void*)0); | ||||
| 311 | avctx->internal->hwaccel_priv_data = NULL((void*)0); | ||||
| 312 | |||||
| 313 | p->hwaccel_serializing = 0; | ||||
| 314 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->parent->hwaccel_mutex); | ||||
| 315 | } | ||||
| 316 | 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" , 317); abort(); } } while (0) | ||||
| 317 | (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" , 317); abort(); } } while (0); | ||||
| 318 | |||||
| 319 | if (p->async_serializing) { | ||||
| 320 | p->async_serializing = 0; | ||||
| 321 | |||||
| 322 | async_unlock(p->parent); | ||||
| 323 | } | ||||
| 324 | |||||
| 325 | pthread_mutex_lockstrict_pthread_mutex_lock(&p->progress_mutex); | ||||
| 326 | |||||
| 327 | atomic_store(&p->state, STATE_INPUT_READY)__c11_atomic_store(&p->state, STATE_INPUT_READY, 5); | ||||
| 328 | |||||
| 329 | pthread_cond_broadcaststrict_pthread_cond_broadcast(&p->progress_cond); | ||||
| 330 | pthread_cond_signalstrict_pthread_cond_signal(&p->output_cond); | ||||
| 331 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->progress_mutex); | ||||
| 332 | } | ||||
| 333 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->mutex); | ||||
| 334 | |||||
| 335 | return NULL((void*)0); | ||||
| 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 | static int update_context_from_thread(AVCodecContext *dst, const AVCodecContext *src, int for_user) | ||||
| 347 | { | ||||
| 348 | const FFCodec *const codec = ffcodec(dst->codec); | ||||
| 349 | int err = 0; | ||||
| 350 | |||||
| 351 | if (dst != src && (for_user || codec->update_thread_context)) { | ||||
| 352 | dst->time_base = src->time_base; | ||||
| 353 | dst->framerate = src->framerate; | ||||
| 354 | dst->width = src->width; | ||||
| 355 | dst->height = src->height; | ||||
| 356 | dst->pix_fmt = src->pix_fmt; | ||||
| 357 | dst->sw_pix_fmt = src->sw_pix_fmt; | ||||
| 358 | |||||
| 359 | dst->coded_width = src->coded_width; | ||||
| 360 | dst->coded_height = src->coded_height; | ||||
| 361 | |||||
| 362 | dst->has_b_frames = src->has_b_frames; | ||||
| 363 | dst->idct_algo = src->idct_algo; | ||||
| 364 | #if FF_API_CODEC_PROPS(62 < 63) | ||||
| 365 | FF_DISABLE_DEPRECATION_WARNINGSGCC diagnostic push
GCC diagnostic ignored "-Wdeprecated-declarations" | ||||
| 366 | dst->properties = src->properties; | ||||
| 367 | FF_ENABLE_DEPRECATION_WARNINGSGCC diagnostic pop | ||||
| 368 | #endif | ||||
| 369 | |||||
| 370 | dst->bits_per_coded_sample = src->bits_per_coded_sample; | ||||
| 371 | dst->sample_aspect_ratio = src->sample_aspect_ratio; | ||||
| 372 | |||||
| 373 | dst->profile = src->profile; | ||||
| 374 | dst->level = src->level; | ||||
| 375 | |||||
| 376 | dst->bits_per_raw_sample = src->bits_per_raw_sample; | ||||
| 377 | dst->color_primaries = src->color_primaries; | ||||
| 378 | |||||
| 379 | dst->alpha_mode = src->alpha_mode; | ||||
| 380 | |||||
| 381 | dst->color_trc = src->color_trc; | ||||
| 382 | dst->colorspace = src->colorspace; | ||||
| 383 | dst->color_range = src->color_range; | ||||
| 384 | dst->chroma_sample_location = src->chroma_sample_location; | ||||
| 385 | |||||
| 386 | dst->sample_rate = src->sample_rate; | ||||
| 387 | dst->sample_fmt = src->sample_fmt; | ||||
| 388 | err = av_channel_layout_copy(&dst->ch_layout, &src->ch_layout); | ||||
| 389 | if (err < 0) | ||||
| 390 | return err; | ||||
| 391 | |||||
| 392 | if (!!dst->hw_frames_ctx != !!src->hw_frames_ctx || | ||||
| 393 | (dst->hw_frames_ctx && dst->hw_frames_ctx->data != src->hw_frames_ctx->data)) { | ||||
| 394 | av_buffer_unref(&dst->hw_frames_ctx); | ||||
| 395 | |||||
| 396 | if (src->hw_frames_ctx) { | ||||
| 397 | dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx); | ||||
| 398 | if (!dst->hw_frames_ctx) | ||||
| 399 | return AVERROR(ENOMEM)(-(12)); | ||||
| 400 | } | ||||
| 401 | } | ||||
| 402 | |||||
| 403 | dst->hwaccel_flags = src->hwaccel_flags; | ||||
| 404 | |||||
| 405 | av_refstruct_replace(&dst->internal->pool, src->internal->pool); | ||||
| 406 | ff_decode_internal_sync(dst, src); | ||||
| 407 | } | ||||
| 408 | |||||
| 409 | if (for_user
| ||||
| 410 | if (codec->update_thread_context_for_user) | ||||
| 411 | err = codec->update_thread_context_for_user(dst, src); | ||||
| 412 | } else { | ||||
| 413 | const PerThreadContext *p_src = src->internal->thread_ctx; | ||||
| 414 | PerThreadContext *p_dst = dst->internal->thread_ctx; | ||||
| 415 | |||||
| 416 | if (codec->update_thread_context) { | ||||
| 417 | err = codec->update_thread_context(dst, src); | ||||
| 418 | if (err < 0) | ||||
| 419 | return err; | ||||
| 420 | } | ||||
| 421 | |||||
| 422 | // reset dst hwaccel state if needed | ||||
| 423 | 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" , 424); abort(); } } while (0) | ||||
| 424 | (!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" , 424); abort(); } } while (0); | ||||
| 425 | if (p_dst->hwaccel_threadsafe
| ||||
| 426 | (!p_src->hwaccel_threadsafe || dst->hwaccel != src->hwaccel)) { | ||||
| 427 | ff_hwaccel_uninit(dst); | ||||
| 428 | p_dst->hwaccel_threadsafe = 0; | ||||
| 429 | } | ||||
| 430 | |||||
| 431 | // propagate hwaccel state for threadsafe hwaccels | ||||
| 432 | if (p_src->hwaccel_threadsafe
| ||||
| 433 | const FFHWAccel *hwaccel = ffhwaccel(src->hwaccel); | ||||
| 434 | if (!dst->hwaccel) { | ||||
| 435 | if (hwaccel->priv_data_size) { | ||||
| |||||
| 436 | 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" , 436); abort(); } } while (0); | ||||
| 437 | |||||
| 438 | dst->internal->hwaccel_priv_data = | ||||
| 439 | av_mallocz(hwaccel->priv_data_size); | ||||
| 440 | if (!dst->internal->hwaccel_priv_data) | ||||
| 441 | return AVERROR(ENOMEM)(-(12)); | ||||
| 442 | } | ||||
| 443 | dst->hwaccel = src->hwaccel; | ||||
| 444 | } | ||||
| 445 | 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" , 445); abort(); } } while (0); | ||||
| 446 | |||||
| 447 | if (hwaccel->update_thread_context) { | ||||
| 448 | err = hwaccel->update_thread_context(dst, src); | ||||
| 449 | if (err < 0) { | ||||
| 450 | av_log(dst, AV_LOG_ERROR16, "Error propagating hwaccel state\n"); | ||||
| 451 | ff_hwaccel_uninit(dst); | ||||
| 452 | return err; | ||||
| 453 | } | ||||
| 454 | } | ||||
| 455 | p_dst->hwaccel_threadsafe = 1; | ||||
| 456 | } | ||||
| 457 | } | ||||
| 458 | |||||
| 459 | return err; | ||||
| 460 | } | ||||
| 461 | |||||
| 462 | /** | ||||
| 463 | * Update the next thread's AVCodecContext with values set by the user. | ||||
| 464 | * | ||||
| 465 | * @param dst The destination context. | ||||
| 466 | * @param src The source context. | ||||
| 467 | * @return 0 on success, negative error code on failure | ||||
| 468 | */ | ||||
| 469 | static int update_context_from_user(AVCodecContext *dst, const AVCodecContext *src) | ||||
| 470 | { | ||||
| 471 | int err; | ||||
| 472 | |||||
| 473 | dst->flags = src->flags; | ||||
| 474 | |||||
| 475 | dst->draw_horiz_band= src->draw_horiz_band; | ||||
| 476 | dst->get_buffer2 = src->get_buffer2; | ||||
| 477 | |||||
| 478 | dst->opaque = src->opaque; | ||||
| 479 | dst->debug = src->debug; | ||||
| 480 | |||||
| 481 | dst->slice_flags = src->slice_flags; | ||||
| 482 | dst->flags2 = src->flags2; | ||||
| 483 | dst->export_side_data = src->export_side_data; | ||||
| 484 | |||||
| 485 | dst->skip_loop_filter = src->skip_loop_filter; | ||||
| 486 | dst->skip_idct = src->skip_idct; | ||||
| 487 | dst->skip_frame = src->skip_frame; | ||||
| 488 | |||||
| 489 | dst->frame_num = src->frame_num; | ||||
| 490 | |||||
| 491 | av_packet_unref(dst->internal->last_pkt_props); | ||||
| 492 | err = av_packet_copy_props(dst->internal->last_pkt_props, src->internal->last_pkt_props); | ||||
| 493 | if (err < 0) | ||||
| 494 | return err; | ||||
| 495 | |||||
| 496 | return 0; | ||||
| 497 | } | ||||
| 498 | |||||
| 499 | static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx, | ||||
| 500 | AVPacket *in_pkt) | ||||
| 501 | { | ||||
| 502 | FrameThreadContext *fctx = p->parent; | ||||
| 503 | PerThreadContext *prev_thread = fctx->prev_thread; | ||||
| 504 | const AVCodec *codec = p->avctx->codec; | ||||
| 505 | int ret; | ||||
| 506 | |||||
| 507 | pthread_mutex_lockstrict_pthread_mutex_lock(&p->mutex); | ||||
| 508 | |||||
| 509 | av_packet_unref(p->avpkt); | ||||
| 510 | av_packet_move_ref(p->avpkt, in_pkt); | ||||
| 511 | |||||
| 512 | if (AVPACKET_IS_EMPTY(p->avpkt)(!(p->avpkt)->data && !(p->avpkt)->side_data_elems )) | ||||
| 513 | p->avctx->internal->draining = 1; | ||||
| 514 | |||||
| 515 | ret = update_context_from_user(p->avctx, user_avctx); | ||||
| 516 | if (ret) { | ||||
| 517 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->mutex); | ||||
| 518 | return ret; | ||||
| 519 | } | ||||
| 520 | atomic_store_explicit__c11_atomic_store(&p->debug_threads, | ||||
| 521 | (p->avctx->debug & FF_DEBUG_THREADS0x00010000) != 0, | ||||
| 522 | memory_order_relaxed); | ||||
| 523 | |||||
| 524 | if (prev_thread) { | ||||
| 525 | if (atomic_load(&prev_thread->state)__c11_atomic_load(&prev_thread->state, 5) == STATE_SETTING_UP) { | ||||
| 526 | pthread_mutex_lockstrict_pthread_mutex_lock(&prev_thread->progress_mutex); | ||||
| 527 | while (atomic_load(&prev_thread->state)__c11_atomic_load(&prev_thread->state, 5) == STATE_SETTING_UP) | ||||
| 528 | pthread_cond_waitstrict_pthread_cond_wait(&prev_thread->progress_cond, &prev_thread->progress_mutex); | ||||
| 529 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&prev_thread->progress_mutex); | ||||
| 530 | } | ||||
| 531 | |||||
| 532 | /* codecs without delay might not be prepared to be called repeatedly here during | ||||
| 533 | * flushing (vp3/theora), and also don't need to be, since from this point on, they | ||||
| 534 | * will always return EOF anyway */ | ||||
| 535 | if (!p->avctx->internal->draining || | ||||
| 536 | (codec->capabilities & AV_CODEC_CAP_DELAY(1 << 5))) { | ||||
| 537 | ret = update_context_from_thread(p->avctx, prev_thread->avctx, 0); | ||||
| 538 | if (ret) { | ||||
| 539 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->mutex); | ||||
| 540 | return ret; | ||||
| 541 | } | ||||
| 542 | } | ||||
| 543 | } | ||||
| 544 | |||||
| 545 | /* transfer the stashed hwaccel state, if any */ | ||||
| 546 | 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" , 546); abort(); } } while (0); | ||||
| 547 | if (!p->hwaccel_threadsafe) { | ||||
| 548 | 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); | ||||
| 549 | 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); | ||||
| 550 | 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); | ||||
| 551 | } | ||||
| 552 | |||||
| 553 | atomic_store(&p->state, STATE_SETTING_UP)__c11_atomic_store(&p->state, STATE_SETTING_UP, 5); | ||||
| 554 | pthread_cond_signalstrict_pthread_cond_signal(&p->input_cond); | ||||
| 555 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->mutex); | ||||
| 556 | |||||
| 557 | fctx->prev_thread = p; | ||||
| 558 | fctx->next_decoding = (fctx->next_decoding + 1) % p->avctx->thread_count; | ||||
| 559 | |||||
| 560 | return 0; | ||||
| 561 | } | ||||
| 562 | |||||
| 563 | int ff_thread_receive_frame(AVCodecContext *avctx, AVFrame *frame, unsigned flags) | ||||
| 564 | { | ||||
| 565 | FrameThreadContext *fctx = avctx->internal->thread_ctx; | ||||
| 566 | int ret = 0; | ||||
| 567 | |||||
| 568 | /* release the async lock, permitting blocked hwaccel threads to | ||||
| 569 | * go forward while we are in this function */ | ||||
| 570 | async_unlock(fctx); | ||||
| 571 | |||||
| 572 | /* submit packets to threads while there are no buffered results to return */ | ||||
| 573 | while (!fctx->df.nb_f && !fctx->result) { | ||||
| 574 | PerThreadContext *p; | ||||
| 575 | |||||
| 576 | if (fctx->next_decoding != fctx->next_finished && | ||||
| 577 | (flags & AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS(1 << 0))) | ||||
| 578 | goto wait_for_result; | ||||
| 579 | |||||
| 580 | /* get a packet to be submitted to the next thread */ | ||||
| 581 | av_packet_unref(fctx->next_pkt); | ||||
| 582 | ret = ff_decode_get_packet(avctx, fctx->next_pkt); | ||||
| 583 | if (ret < 0 && ret != AVERROR_EOF(-(int)(('E') | (('O') << 8) | (('F') << 16) | (( unsigned)(' ') << 24)))) | ||||
| 584 | goto finish; | ||||
| 585 | |||||
| 586 | ret = submit_packet(&fctx->threads[fctx->next_decoding], avctx, | ||||
| 587 | fctx->next_pkt); | ||||
| 588 | if (ret < 0) | ||||
| 589 | goto finish; | ||||
| 590 | |||||
| 591 | /* do not return any frames until all threads have something to do */ | ||||
| 592 | if (fctx->next_decoding != fctx->next_finished && | ||||
| 593 | !avctx->internal->draining) | ||||
| 594 | continue; | ||||
| 595 | |||||
| 596 | wait_for_result: | ||||
| 597 | p = &fctx->threads[fctx->next_finished]; | ||||
| 598 | fctx->next_finished = (fctx->next_finished + 1) % avctx->thread_count; | ||||
| 599 | |||||
| 600 | if (atomic_load(&p->state)__c11_atomic_load(&p->state, 5) != STATE_INPUT_READY) { | ||||
| 601 | pthread_mutex_lockstrict_pthread_mutex_lock(&p->progress_mutex); | ||||
| 602 | while (atomic_load_explicit__c11_atomic_load(&p->state, memory_order_relaxed) != STATE_INPUT_READY) | ||||
| 603 | pthread_cond_waitstrict_pthread_cond_wait(&p->output_cond, &p->progress_mutex); | ||||
| 604 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->progress_mutex); | ||||
| 605 | } | ||||
| 606 | |||||
| 607 | update_context_from_thread(avctx, p->avctx, 1); | ||||
| 608 | fctx->result = p->result; | ||||
| 609 | p->result = 0; | ||||
| 610 | if (p->df.nb_f) | ||||
| 611 | FFSWAP(DecodedFrames, fctx->df, p->df)do{DecodedFrames SWAP_tmp= p->df; p->df= fctx->df; fctx ->df= SWAP_tmp;}while(0); | ||||
| 612 | } | ||||
| 613 | |||||
| 614 | /* a thread may return multiple frames AND an error | ||||
| 615 | * we first return all the frames, then the error */ | ||||
| 616 | if (fctx->df.nb_f) { | ||||
| 617 | decoded_frames_pop(&fctx->df, frame); | ||||
| 618 | ret = 0; | ||||
| 619 | } else { | ||||
| 620 | ret = fctx->result; | ||||
| 621 | fctx->result = 0; | ||||
| 622 | } | ||||
| 623 | |||||
| 624 | finish: | ||||
| 625 | async_lock(fctx); | ||||
| 626 | return ret; | ||||
| 627 | } | ||||
| 628 | |||||
| 629 | void ff_thread_report_progress(ThreadFrame *f, int n, int field) | ||||
| 630 | { | ||||
| 631 | PerThreadContext *p; | ||||
| 632 | atomic_int *progress = f->progress ? f->progress->progress : NULL((void*)0); | ||||
| 633 | |||||
| 634 | if (!progress || | ||||
| 635 | atomic_load_explicit__c11_atomic_load(&progress[field], memory_order_relaxed) >= n) | ||||
| 636 | return; | ||||
| 637 | |||||
| 638 | p = f->owner[field]->internal->thread_ctx; | ||||
| 639 | |||||
| 640 | if (atomic_load_explicit__c11_atomic_load(&p->debug_threads, memory_order_relaxed)) | ||||
| 641 | av_log(f->owner[field], AV_LOG_DEBUG48, | ||||
| 642 | "%p finished %d field %d\n", progress, n, field); | ||||
| 643 | |||||
| 644 | pthread_mutex_lockstrict_pthread_mutex_lock(&p->progress_mutex); | ||||
| 645 | |||||
| 646 | atomic_store_explicit__c11_atomic_store(&progress[field], n, memory_order_release); | ||||
| 647 | |||||
| 648 | pthread_cond_broadcaststrict_pthread_cond_broadcast(&p->progress_cond); | ||||
| 649 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->progress_mutex); | ||||
| 650 | } | ||||
| 651 | |||||
| 652 | void ff_thread_await_progress(const ThreadFrame *f, int n, int field) | ||||
| 653 | { | ||||
| 654 | PerThreadContext *p; | ||||
| 655 | atomic_int *progress = f->progress ? f->progress->progress : NULL((void*)0); | ||||
| 656 | |||||
| 657 | if (!progress || | ||||
| 658 | atomic_load_explicit__c11_atomic_load(&progress[field], memory_order_acquire) >= n) | ||||
| 659 | return; | ||||
| 660 | |||||
| 661 | p = f->owner[field]->internal->thread_ctx; | ||||
| 662 | |||||
| 663 | if (atomic_load_explicit__c11_atomic_load(&p->debug_threads, memory_order_relaxed)) | ||||
| 664 | av_log(f->owner[field], AV_LOG_DEBUG48, | ||||
| 665 | "thread awaiting %d field %d from %p\n", n, field, progress); | ||||
| 666 | |||||
| 667 | pthread_mutex_lockstrict_pthread_mutex_lock(&p->progress_mutex); | ||||
| 668 | while (atomic_load_explicit__c11_atomic_load(&progress[field], memory_order_relaxed) < n) | ||||
| 669 | pthread_cond_waitstrict_pthread_cond_wait(&p->progress_cond, &p->progress_mutex); | ||||
| 670 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->progress_mutex); | ||||
| 671 | } | ||||
| 672 | |||||
| 673 | void ff_thread_finish_setup(AVCodecContext *avctx) { | ||||
| 674 | PerThreadContext *p; | ||||
| 675 | |||||
| 676 | if (!(avctx->active_thread_type&FF_THREAD_FRAME1)) return; | ||||
| 677 | |||||
| 678 | p = avctx->internal->thread_ctx; | ||||
| 679 | |||||
| 680 | p->hwaccel_threadsafe = avctx->hwaccel && | ||||
| 681 | (ffhwaccel(avctx->hwaccel)->caps_internal & HWACCEL_CAP_THREAD_SAFE(1 << 1)); | ||||
| 682 | |||||
| 683 | if (hwaccel_serial(avctx) && !p->hwaccel_serializing) { | ||||
| 684 | pthread_mutex_lockstrict_pthread_mutex_lock(&p->parent->hwaccel_mutex); | ||||
| 685 | p->hwaccel_serializing = 1; | ||||
| 686 | } | ||||
| 687 | |||||
| 688 | /* this assumes that no hwaccel calls happen before ff_thread_finish_setup() */ | ||||
| 689 | if (avctx->hwaccel && | ||||
| 690 | !(ffhwaccel(avctx->hwaccel)->caps_internal & HWACCEL_CAP_ASYNC_SAFE(1 << 0))) { | ||||
| 691 | p->async_serializing = 1; | ||||
| 692 | |||||
| 693 | async_lock(p->parent); | ||||
| 694 | } | ||||
| 695 | |||||
| 696 | /* thread-unsafe hwaccels share a single private data instance, so we | ||||
| 697 | * save hwaccel state for passing to the next thread; | ||||
| 698 | * this is done here so that this worker thread can wipe its own hwaccel | ||||
| 699 | * state after decoding, without requiring synchronization */ | ||||
| 700 | 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" , 700); abort(); } } while (0); | ||||
| 701 | if (hwaccel_serial(avctx)) { | ||||
| 702 | p->parent->stash_hwaccel = avctx->hwaccel; | ||||
| 703 | p->parent->stash_hwaccel_context = avctx->hwaccel_context; | ||||
| 704 | p->parent->stash_hwaccel_priv = avctx->internal->hwaccel_priv_data; | ||||
| 705 | } | ||||
| 706 | |||||
| 707 | pthread_mutex_lockstrict_pthread_mutex_lock(&p->progress_mutex); | ||||
| 708 | if(atomic_load(&p->state)__c11_atomic_load(&p->state, 5) == STATE_SETUP_FINISHED){ | ||||
| 709 | av_log(avctx, AV_LOG_WARNING24, "Multiple ff_thread_finish_setup() calls\n"); | ||||
| 710 | } | ||||
| 711 | |||||
| 712 | atomic_store(&p->state, STATE_SETUP_FINISHED)__c11_atomic_store(&p->state, STATE_SETUP_FINISHED, 5); | ||||
| 713 | |||||
| 714 | pthread_cond_broadcaststrict_pthread_cond_broadcast(&p->progress_cond); | ||||
| 715 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->progress_mutex); | ||||
| 716 | } | ||||
| 717 | |||||
| 718 | /// Waits for all threads to finish. | ||||
| 719 | static av_cold__attribute__((cold)) void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count) | ||||
| 720 | { | ||||
| 721 | int i; | ||||
| 722 | |||||
| 723 | async_unlock(fctx); | ||||
| 724 | |||||
| 725 | for (i = 0; i < thread_count; i++) { | ||||
| 726 | PerThreadContext *p = &fctx->threads[i]; | ||||
| 727 | |||||
| 728 | if (atomic_load(&p->state)__c11_atomic_load(&p->state, 5) != STATE_INPUT_READY) { | ||||
| 729 | pthread_mutex_lockstrict_pthread_mutex_lock(&p->progress_mutex); | ||||
| 730 | while (atomic_load(&p->state)__c11_atomic_load(&p->state, 5) != STATE_INPUT_READY) | ||||
| 731 | pthread_cond_waitstrict_pthread_cond_wait(&p->output_cond, &p->progress_mutex); | ||||
| 732 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->progress_mutex); | ||||
| 733 | } | ||||
| 734 | } | ||||
| 735 | |||||
| 736 | async_lock(fctx); | ||||
| 737 | } | ||||
| 738 | |||||
| 739 | #define OFF(member) offsetof(FrameThreadContext, member)__builtin_offsetof(FrameThreadContext, member) | ||||
| 740 | 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 } | ||||
| 741 | (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 } | ||||
| 742 | (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 }; | ||||
| 743 | #undef OFF | ||||
| 744 | |||||
| 745 | #define OFF(member) offsetof(PerThreadContext, member)__builtin_offsetof(PerThreadContext, member) | ||||
| 746 | 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 } | ||||
| 747 | (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 } | ||||
| 748 | (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 }; | ||||
| 749 | #undef OFF | ||||
| 750 | |||||
| 751 | av_cold__attribute__((cold)) void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) | ||||
| 752 | { | ||||
| 753 | FrameThreadContext *fctx = avctx->internal->thread_ctx; | ||||
| 754 | const FFCodec *codec = ffcodec(avctx->codec); | ||||
| 755 | int i; | ||||
| 756 | |||||
| 757 | park_frame_worker_threads(fctx, thread_count); | ||||
| 758 | |||||
| 759 | for (i = 0; i < thread_count; i++) { | ||||
| 760 | PerThreadContext *p = &fctx->threads[i]; | ||||
| 761 | AVCodecContext *ctx = p->avctx; | ||||
| 762 | |||||
| 763 | if (ctx->internal) { | ||||
| 764 | if (p->thread_init == INITIALIZED) { | ||||
| 765 | pthread_mutex_lockstrict_pthread_mutex_lock(&p->mutex); | ||||
| 766 | p->die = 1; | ||||
| 767 | pthread_cond_signalstrict_pthread_cond_signal(&p->input_cond); | ||||
| 768 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->mutex); | ||||
| 769 | |||||
| 770 | pthread_joinstrict_pthread_join(p->thread, NULL((void*)0)); | ||||
| 771 | } | ||||
| 772 | if (codec->close && p->thread_init != UNINITIALIZED) | ||||
| 773 | codec->close(ctx); | ||||
| 774 | |||||
| 775 | /* When using a threadsafe hwaccel, this is where | ||||
| 776 | * each thread's context is uninit'd and freed. */ | ||||
| 777 | ff_hwaccel_uninit(ctx); | ||||
| 778 | |||||
| 779 | if (ctx->priv_data) { | ||||
| 780 | if (codec->p.priv_class) | ||||
| 781 | av_opt_free(ctx->priv_data); | ||||
| 782 | av_freep(&ctx->priv_data); | ||||
| 783 | } | ||||
| 784 | |||||
| 785 | av_refstruct_unref(&ctx->internal->pool); | ||||
| 786 | av_packet_free(&ctx->internal->in_pkt); | ||||
| 787 | av_packet_free(&ctx->internal->last_pkt_props); | ||||
| 788 | ff_decode_internal_uninit(ctx); | ||||
| 789 | av_freep(&ctx->internal); | ||||
| 790 | av_buffer_unref(&ctx->hw_frames_ctx); | ||||
| 791 | av_frame_side_data_free(&ctx->decoded_side_data, | ||||
| 792 | &ctx->nb_decoded_side_data); | ||||
| 793 | } | ||||
| 794 | |||||
| 795 | decoded_frames_free(&p->df); | ||||
| 796 | |||||
| 797 | ff_pthread_free(p, per_thread_offsets); | ||||
| 798 | av_packet_free(&p->avpkt); | ||||
| 799 | |||||
| 800 | av_freep(&p->avctx); | ||||
| 801 | } | ||||
| 802 | |||||
| 803 | decoded_frames_free(&fctx->df); | ||||
| 804 | av_packet_free(&fctx->next_pkt); | ||||
| 805 | |||||
| 806 | av_freep(&fctx->threads); | ||||
| 807 | ff_pthread_free(fctx, thread_ctx_offsets); | ||||
| 808 | |||||
| 809 | /* if we have stashed hwaccel state, move it to the user-facing context, | ||||
| 810 | * so it will be freed in ff_codec_close() */ | ||||
| 811 | 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" , 811); abort(); } } while (0); | ||||
| 812 | 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); | ||||
| 813 | 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); | ||||
| 814 | 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); | ||||
| 815 | |||||
| 816 | av_freep(&avctx->internal->thread_ctx); | ||||
| 817 | } | ||||
| 818 | |||||
| 819 | static av_cold__attribute__((cold)) int init_thread(PerThreadContext *p, int *threads_to_free, | ||||
| 820 | FrameThreadContext *fctx, AVCodecContext *avctx, | ||||
| 821 | const FFCodec *codec, int first) | ||||
| 822 | { | ||||
| 823 | AVCodecContext *copy; | ||||
| 824 | int err; | ||||
| 825 | |||||
| 826 | atomic_init__c11_atomic_init(&p->state, STATE_INPUT_READY); | ||||
| 827 | |||||
| 828 | copy = av_memdup(avctx, sizeof(*avctx)); | ||||
| 829 | if (!copy) | ||||
| 830 | return AVERROR(ENOMEM)(-(12)); | ||||
| 831 | copy->priv_data = NULL((void*)0); | ||||
| 832 | copy->decoded_side_data = NULL((void*)0); | ||||
| 833 | copy->nb_decoded_side_data = 0; | ||||
| 834 | |||||
| 835 | /* From now on, this PerThreadContext will be cleaned up by | ||||
| 836 | * ff_frame_thread_free in case of errors. */ | ||||
| 837 | (*threads_to_free)++; | ||||
| 838 | |||||
| 839 | p->parent = fctx; | ||||
| 840 | p->avctx = copy; | ||||
| 841 | |||||
| 842 | copy->internal = ff_decode_internal_alloc(); | ||||
| 843 | if (!copy->internal) | ||||
| 844 | return AVERROR(ENOMEM)(-(12)); | ||||
| 845 | ff_decode_internal_sync(copy, avctx); | ||||
| 846 | copy->internal->thread_ctx = p; | ||||
| 847 | copy->internal->progress_frame_pool = avctx->internal->progress_frame_pool; | ||||
| 848 | |||||
| 849 | copy->delay = avctx->delay; | ||||
| 850 | |||||
| 851 | if (codec->priv_data_size) { | ||||
| 852 | copy->priv_data = av_mallocz(codec->priv_data_size); | ||||
| 853 | if (!copy->priv_data) | ||||
| 854 | return AVERROR(ENOMEM)(-(12)); | ||||
| 855 | |||||
| 856 | if (codec->p.priv_class) { | ||||
| 857 | *(const AVClass **)copy->priv_data = codec->p.priv_class; | ||||
| 858 | err = av_opt_copy(copy->priv_data, avctx->priv_data); | ||||
| 859 | if (err < 0) | ||||
| 860 | return err; | ||||
| 861 | } | ||||
| 862 | } | ||||
| 863 | |||||
| 864 | err = ff_pthread_init(p, per_thread_offsets); | ||||
| 865 | if (err < 0) | ||||
| 866 | return err; | ||||
| 867 | |||||
| 868 | if (!(p->avpkt = av_packet_alloc())) | ||||
| 869 | return AVERROR(ENOMEM)(-(12)); | ||||
| 870 | |||||
| 871 | copy->internal->is_frame_mt = 1; | ||||
| 872 | if (!first) | ||||
| 873 | copy->internal->is_copy = 1; | ||||
| 874 | |||||
| 875 | copy->internal->in_pkt = av_packet_alloc(); | ||||
| 876 | if (!copy->internal->in_pkt) | ||||
| 877 | return AVERROR(ENOMEM)(-(12)); | ||||
| 878 | |||||
| 879 | copy->internal->last_pkt_props = av_packet_alloc(); | ||||
| 880 | if (!copy->internal->last_pkt_props) | ||||
| 881 | return AVERROR(ENOMEM)(-(12)); | ||||
| 882 | |||||
| 883 | if (codec->init) { | ||||
| 884 | err = codec->init(copy); | ||||
| 885 | if (err < 0) { | ||||
| 886 | if (codec->caps_internal & FF_CODEC_CAP_INIT_CLEANUP(1 << 1)) | ||||
| 887 | p->thread_init = NEEDS_CLOSE; | ||||
| 888 | return err; | ||||
| 889 | } | ||||
| 890 | } | ||||
| 891 | p->thread_init = NEEDS_CLOSE; | ||||
| 892 | |||||
| 893 | if (first) { | ||||
| 894 | update_context_from_thread(avctx, copy, 1); | ||||
| 895 | |||||
| 896 | av_frame_side_data_free(&avctx->decoded_side_data, &avctx->nb_decoded_side_data); | ||||
| 897 | for (int i = 0; i < copy->nb_decoded_side_data; i++) { | ||||
| 898 | err = av_frame_side_data_clone(&avctx->decoded_side_data, | ||||
| 899 | &avctx->nb_decoded_side_data, | ||||
| 900 | copy->decoded_side_data[i], 0); | ||||
| 901 | if (err < 0) | ||||
| 902 | return err; | ||||
| 903 | } | ||||
| 904 | } | ||||
| 905 | |||||
| 906 | atomic_init__c11_atomic_init(&p->debug_threads, (copy->debug & FF_DEBUG_THREADS0x00010000) != 0); | ||||
| 907 | |||||
| 908 | err = AVERROR(pthread_create(&p->thread, NULL, frame_worker_thread, p))(-(pthread_create(&p->thread, ((void*)0), frame_worker_thread , p))); | ||||
| 909 | if (err < 0) | ||||
| 910 | return err; | ||||
| 911 | p->thread_init = INITIALIZED; | ||||
| 912 | |||||
| 913 | return 0; | ||||
| 914 | } | ||||
| 915 | |||||
| 916 | av_cold__attribute__((cold)) int ff_frame_thread_init(AVCodecContext *avctx) | ||||
| 917 | { | ||||
| 918 | int thread_count = avctx->thread_count; | ||||
| 919 | const FFCodec *codec = ffcodec(avctx->codec); | ||||
| 920 | FrameThreadContext *fctx; | ||||
| 921 | int err, i = 0; | ||||
| 922 | |||||
| 923 | if (!thread_count) { | ||||
| 924 | int nb_cpus = av_cpu_count(); | ||||
| 925 | // use number of cores + 1 as thread count if there is more than one | ||||
| 926 | if (nb_cpus > 1) | ||||
| 927 | thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS)((nb_cpus + 1) > (16) ? (16) : (nb_cpus + 1)); | ||||
| 928 | else | ||||
| 929 | thread_count = avctx->thread_count = 1; | ||||
| 930 | } | ||||
| 931 | |||||
| 932 | if (thread_count <= 1) { | ||||
| 933 | avctx->active_thread_type = 0; | ||||
| 934 | return 0; | ||||
| 935 | } | ||||
| 936 | |||||
| 937 | avctx->internal->thread_ctx = fctx = av_mallocz(sizeof(FrameThreadContext)); | ||||
| 938 | if (!fctx) | ||||
| 939 | return AVERROR(ENOMEM)(-(12)); | ||||
| 940 | |||||
| 941 | err = ff_pthread_init(fctx, thread_ctx_offsets); | ||||
| 942 | if (err < 0) { | ||||
| 943 | ff_pthread_free(fctx, thread_ctx_offsets); | ||||
| 944 | av_freep(&avctx->internal->thread_ctx); | ||||
| 945 | return err; | ||||
| 946 | } | ||||
| 947 | |||||
| 948 | fctx->next_pkt = av_packet_alloc(); | ||||
| 949 | if (!fctx->next_pkt) | ||||
| 950 | return AVERROR(ENOMEM)(-(12)); | ||||
| 951 | |||||
| 952 | fctx->async_lock = 1; | ||||
| 953 | |||||
| 954 | if (codec->p.type == AVMEDIA_TYPE_VIDEO) | ||||
| 955 | avctx->delay = avctx->thread_count - 1; | ||||
| 956 | |||||
| 957 | fctx->threads = av_calloc(thread_count, sizeof(*fctx->threads)); | ||||
| 958 | if (!fctx->threads) { | ||||
| 959 | err = AVERROR(ENOMEM)(-(12)); | ||||
| 960 | goto error; | ||||
| 961 | } | ||||
| 962 | |||||
| 963 | for (; i < thread_count; ) { | ||||
| 964 | PerThreadContext *p = &fctx->threads[i]; | ||||
| 965 | int first = !i; | ||||
| 966 | |||||
| 967 | err = init_thread(p, &i, fctx, avctx, codec, first); | ||||
| 968 | if (err < 0) | ||||
| 969 | goto error; | ||||
| 970 | } | ||||
| 971 | |||||
| 972 | return 0; | ||||
| 973 | |||||
| 974 | error: | ||||
| 975 | ff_frame_thread_free(avctx, i); | ||||
| 976 | return err; | ||||
| 977 | } | ||||
| 978 | |||||
| 979 | av_cold__attribute__((cold)) void ff_thread_flush(AVCodecContext *avctx) | ||||
| 980 | { | ||||
| 981 | int i; | ||||
| 982 | FrameThreadContext *fctx = avctx->internal->thread_ctx; | ||||
| 983 | |||||
| 984 | if (!fctx) return; | ||||
| |||||
| 985 | |||||
| 986 | park_frame_worker_threads(fctx, avctx->thread_count); | ||||
| 987 | if (fctx->prev_thread) { | ||||
| 988 | if (fctx->prev_thread != &fctx->threads[0]) | ||||
| 989 | update_context_from_thread(fctx->threads[0].avctx, fctx->prev_thread->avctx, 0); | ||||
| 990 | } | ||||
| 991 | |||||
| 992 | fctx->next_decoding = fctx->next_finished = 0; | ||||
| 993 | fctx->prev_thread = NULL((void*)0); | ||||
| 994 | |||||
| 995 | decoded_frames_flush(&fctx->df); | ||||
| 996 | fctx->result = 0; | ||||
| 997 | |||||
| 998 | for (i = 0; i < avctx->thread_count; i++) { | ||||
| 999 | PerThreadContext *p = &fctx->threads[i]; | ||||
| 1000 | |||||
| 1001 | decoded_frames_flush(&p->df); | ||||
| 1002 | p->result = 0; | ||||
| 1003 | |||||
| 1004 | avcodec_flush_buffers(p->avctx); | ||||
| 1005 | } | ||||
| 1006 | } | ||||
| 1007 | |||||
| 1008 | int ff_thread_can_start_frame(AVCodecContext *avctx) | ||||
| 1009 | { | ||||
| 1010 | if ((avctx->active_thread_type & FF_THREAD_FRAME1) && | ||||
| 1011 | ffcodec(avctx->codec)->update_thread_context) { | ||||
| 1012 | PerThreadContext *p = avctx->internal->thread_ctx; | ||||
| 1013 | |||||
| 1014 | if (atomic_load(&p->state)__c11_atomic_load(&p->state, 5) != STATE_SETTING_UP) | ||||
| 1015 | return 0; | ||||
| 1016 | } | ||||
| 1017 | |||||
| 1018 | return 1; | ||||
| 1019 | } | ||||
| 1020 | |||||
| 1021 | static int thread_get_buffer_internal(AVCodecContext *avctx, AVFrame *f, int flags) | ||||
| 1022 | { | ||||
| 1023 | PerThreadContext *p; | ||||
| 1024 | int err; | ||||
| 1025 | |||||
| 1026 | if (!(avctx->active_thread_type & FF_THREAD_FRAME1)) | ||||
| 1027 | return ff_get_buffer(avctx, f, flags); | ||||
| 1028 | |||||
| 1029 | p = avctx->internal->thread_ctx; | ||||
| 1030 | if (atomic_load(&p->state)__c11_atomic_load(&p->state, 5) != STATE_SETTING_UP && | ||||
| 1031 | ffcodec(avctx->codec)->update_thread_context) { | ||||
| 1032 | av_log(avctx, AV_LOG_ERROR16, "get_buffer() cannot be called after ff_thread_finish_setup()\n"); | ||||
| 1033 | return -1; | ||||
| 1034 | } | ||||
| 1035 | |||||
| 1036 | pthread_mutex_lockstrict_pthread_mutex_lock(&p->parent->buffer_mutex); | ||||
| 1037 | err = ff_get_buffer(avctx, f, flags); | ||||
| 1038 | |||||
| 1039 | pthread_mutex_unlockstrict_pthread_mutex_unlock(&p->parent->buffer_mutex); | ||||
| 1040 | |||||
| 1041 | return err; | ||||
| 1042 | } | ||||
| 1043 | |||||
| 1044 | int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f, int flags) | ||||
| 1045 | { | ||||
| 1046 | int ret = thread_get_buffer_internal(avctx, f, flags); | ||||
| 1047 | if (ret < 0) | ||||
| 1048 | av_log(avctx, AV_LOG_ERROR16, "thread_get_buffer() failed\n"); | ||||
| 1049 | return ret; | ||||
| 1050 | } | ||||
| 1051 | |||||
| 1052 | int ff_thread_get_ext_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) | ||||
| 1053 | { | ||||
| 1054 | int ret; | ||||
| 1055 | |||||
| 1056 | f->owner[0] = f->owner[1] = avctx; | ||||
| 1057 | if (!(avctx->active_thread_type & FF_THREAD_FRAME1)) | ||||
| 1058 | return ff_get_buffer(avctx, f->f, flags); | ||||
| 1059 | |||||
| 1060 | f->progress = av_refstruct_allocz(sizeof(*f->progress)); | ||||
| 1061 | if (!f->progress) | ||||
| 1062 | return AVERROR(ENOMEM)(-(12)); | ||||
| 1063 | |||||
| 1064 | atomic_init__c11_atomic_init(&f->progress->progress[0], -1); | ||||
| 1065 | atomic_init__c11_atomic_init(&f->progress->progress[1], -1); | ||||
| 1066 | |||||
| 1067 | ret = ff_thread_get_buffer(avctx, f->f, flags); | ||||
| 1068 | if (ret) | ||||
| 1069 | av_refstruct_unref(&f->progress); | ||||
| 1070 | return ret; | ||||
| 1071 | } | ||||
| 1072 | |||||
| 1073 | void ff_thread_release_ext_buffer(ThreadFrame *f) | ||||
| 1074 | { | ||||
| 1075 | av_refstruct_unref(&f->progress); | ||||
| 1076 | f->owner[0] = f->owner[1] = NULL((void*)0); | ||||
| 1077 | if (f->f) | ||||
| 1078 | av_frame_unref(f->f); | ||||
| 1079 | } | ||||
| 1080 | |||||
| 1081 | av_cold__attribute__((cold)) enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset) | ||||
| 1082 | { | ||||
| 1083 | PerThreadContext *p; | ||||
| 1084 | const void *ref; | ||||
| 1085 | |||||
| 1086 | if (!avctx->internal->is_copy) | ||||
| 1087 | return avctx->active_thread_type & FF_THREAD_FRAME1 ? | ||||
| 1088 | FF_THREAD_IS_FIRST_THREAD : FF_THREAD_NO_FRAME_THREADING; | ||||
| 1089 | |||||
| 1090 | p = avctx->internal->thread_ctx; | ||||
| 1091 | |||||
| 1092 | 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" , 1092); abort(); } } while (0); | ||||
| 1093 | |||||
| 1094 | memcpy(&ref, (const char*)p->parent->threads[0].avctx->priv_data + offset, sizeof(ref)); | ||||
| 1095 | 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" , 1095); abort(); } } while (0); | ||||
| 1096 | av_refstruct_replace((char*)avctx->priv_data + offset, ref); | ||||
| 1097 | |||||
| 1098 | return FF_THREAD_IS_COPY; | ||||
| 1099 | } | ||||
| 1100 | |||||
| 1101 | int ff_thread_get_packet(AVCodecContext *avctx, AVPacket *pkt) | ||||
| 1102 | { | ||||
| 1103 | PerThreadContext *p = avctx->internal->thread_ctx; | ||||
| 1104 | |||||
| 1105 | if (!AVPACKET_IS_EMPTY(p->avpkt)(!(p->avpkt)->data && !(p->avpkt)->side_data_elems )) { | ||||
| 1106 | av_packet_move_ref(pkt, p->avpkt); | ||||
| 1107 | return 0; | ||||
| 1108 | } | ||||
| 1109 | |||||
| 1110 | return avctx->internal->draining ? AVERROR_EOF(-(int)(('E') | (('O') << 8) | (('F') << 16) | (( unsigned)(' ') << 24))) : AVERROR(EAGAIN)(-(11)); | ||||
| 1111 | } |
| 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 */ |