From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id B21364418C for ; Wed, 31 Aug 2022 02:54:24 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 69F2E68BB0D; Wed, 31 Aug 2022 05:54:22 +0300 (EEST) Received: from EUR05-DB8-obe.outbound.protection.outlook.com (mail-db8eur05olkn2022.outbound.protection.outlook.com [40.92.89.22]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id F32E768B9C5 for ; Wed, 31 Aug 2022 05:54:15 +0300 (EEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=GYpl4Qa3xda6DB/ralK5z8z9/+ZvApJWrzr/C+OE3p0PevGCuq9rh5wy1d/CVmOY2U1AfjIQLkKzXcoyGGJWajCj6uQAnx2iiLao2jUnA6PMdeVXvMG3zjwRSnd4ZvsI7zt5K2BWg5409H5soSbbRqy9/I/fUkh5vJtY1+i5/O6QGHnsA3B4Sw5VwAZbgG8LtLbQx9Ccw1QscdWx7t6u8q3nbDdzxa5e+L0DKkIVmfzFNXZRToqEtJMWN0sMeI94nI3NXJ+QK2VCvxHLNRi1TxR9YrturyUjiZ03V+5EhwDYsfra10qdmwYuERMFNLNXRCwb9eg51Y7xpvGdpfp04A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=82P3/fG0xoNPmkYT3w54juSTJ5JeqpCwiPeX4WB5FHs=; b=Nzin5ZcFPqjm4wzfkogg4cVZV0nXvZCjzq5u5/sDj5SPkHtOLuyz+ePV+xn7KeLtbw1sSZp3aUCQVVC3EF8Tc17pkgzfAox9O+1YN8syX5G51M4rGZIVX29WKGp6Ry+kEow729qokEP3Xg7QoB9Ey8a0GLua7AzNlt5MqMSdEiuUirUzxr3T4zZjliENkUAyKvFPHUAnUDh/QB4hcQk2lJ6+YHcWTIjVOUuluIq7yiEGPGvoDMtRCzcuiKMi0IgGv/8A4l5hDV9AP0n9mZ23CexkKhEM+LO/HMe4JY554c+fLfJ92N1EFOOYfUN6Tq6WQgefksmgLjG6bv2QhC92bg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=82P3/fG0xoNPmkYT3w54juSTJ5JeqpCwiPeX4WB5FHs=; b=trIpIl4ejyMOerTOpxWVT3nOtyxcISdSFNuTKHRlEUhQnZos8nhIiIXYHsxwdzTPAC8yX9goYyAnxWWFOmKZNjZf6HkVuhXQwwdsYHMqtMI9eYqR6sfuk6wyXpkRfpo5LmDBbqgWJRDdZyL9z8LNFygNKfS8ElOI5jCiAkrtcRxrcaIUDLcYn5Dxgf9AZHmw4mpwhu7tymOyZxepbzg51siGT0CMWcRKEWzaP/RMKtTGpvljFvQxiujTdj0pB7uBWtISFxEx/7YZKnr4dSMXdqzmVu5tIzsmTznd0vfE8BfIDXj+WBCR6WlFEh43x4lMDmqeozZqLg9rAoKgaLYA9Q== Received: from GV1P250MB0737.EURP250.PROD.OUTLOOK.COM (2603:10a6:150:8e::17) by AS8P250MB0379.EURP250.PROD.OUTLOOK.COM (2603:10a6:20b:37f::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5588.10; Wed, 31 Aug 2022 02:54:14 +0000 Received: from GV1P250MB0737.EURP250.PROD.OUTLOOK.COM ([fe80::90cc:8832:55f1:c7d6]) by GV1P250MB0737.EURP250.PROD.OUTLOOK.COM ([fe80::90cc:8832:55f1:c7d6%7]) with mapi id 15.20.5588.010; Wed, 31 Aug 2022 02:54:14 +0000 Message-ID: Date: Wed, 31 Aug 2022 04:54:12 +0200 Content-Language: en-US To: ffmpeg-devel@ffmpeg.org References: <20220823190326.249-1-lukas.fellechner@gmx.net> <20220823190326.249-3-lukas.fellechner@gmx.net> From: Andreas Rheinhardt In-Reply-To: <20220823190326.249-3-lukas.fellechner@gmx.net> X-TMN: [8hPAFA8UntQQtgGXkBrxbh2OcgRHi6vb] X-ClientProxiedBy: ZR0P278CA0099.CHEP278.PROD.OUTLOOK.COM (2603:10a6:910:23::14) To GV1P250MB0737.EURP250.PROD.OUTLOOK.COM (2603:10a6:150:8e::17) X-Microsoft-Original-Message-ID: <214cb5fd-5a46-9f8c-733d-bfde24cbb144@outlook.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 797d8763-8175-40e8-8355-08da8afc166b X-MS-TrafficTypeDiagnostic: AS8P250MB0379:EE_ X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: a6wadwd1UR7n69mPLr4Tr0msLCxlCZqdE0zzDlBrRzh5Bg4/xucnP7BL+fxcEAn5TXAMpQl0A0U1eLCYaEFPJu/sD/xNMZMIJSi5yCqKFPlpR6URGuvzKa0yWU0RO59istr8RGowFSITJ0h3OOq9fyNoda2MQKjpfGqOTk6XCoYPRZbh1X6x4T7ZJbfXXoGj4Edcu/QNBudGNApjwdvCinnNXEG7jI4kMG9dL/R1UMpSDi8fxE8Sa0hZThSMPXW2T3uTI4rBx1pSnjFrK3DVxWm3N50KUkQhu6mWytc3NgsVsKyLyFD6V9eTY6o8dKOYzmFTO5e9ordEDIR/CbNI4sa0ueClMSO1z9dFfZa0EVYmFRx7i0DmKoGmzDM40L4lOx/1yASFrZ9DaxhF+7DwNUtDFxUOojtznio79Y2Oq0BUoANfg9A6KZURdgBjpZ8z7QWYoHOf83mOSUP6p5vr6Gr/z4qiDyMi5RYXDbF5sQiTUi6snkfidYKQKzOI6MIzo6sISUF8Bvay2xNQtlyWD/QVGmTaTxbQEZunRY3+iBIlCvDqecPDAB5ERRhcPXkRUL4MmAzWAUi5837THwdhYGegmLqbCg4As60V5e+prvP18y512VDCpvZUZxcaefOPmAsbQTg2cmarP7ndhQt5HBFR8nHMQi9r90eYPln9o5msuKvts5yDZOsVKTAskq3O X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?b2k2QXpNSkN6c3ZYM2dHUytMb0s0OURSNUlrb3AvMHNRRzVFRm5FZExKRnhj?= =?utf-8?B?NWV5b3piWG92ekRwajgvSVNsdVBWR2JITS9oQ1NJQit0VmpPWG9LNno0WThR?= =?utf-8?B?UWdmRjRMQWdhcHlSdlFVL213RlZJSUlOdkI1d04xdlpVMmk1NEVUWTJ6WDg2?= =?utf-8?B?VDNLM1Njb25Xd1V0QWI4M0dtYjZoMldvM0xmdEpYdUh4K3JxTmRKWThrZ05P?= =?utf-8?B?SWtFR1JXaTdSVWVkMmg0cFBWVWV2MUlQR3NNM0hSUk9VQnJKNGhmanduanBG?= =?utf-8?B?dzNjZnpRZFZZd0hjNjIxbHpDSk5lRCtNYXFEZ1M5U01sZDFsUGs3cHgwZkoy?= =?utf-8?B?UEJBYkhpd0dpNGNwL1M2K1phdG51dlU0VUZNNkxyd2EyT1ZiWUxQL2x5M3FI?= =?utf-8?B?d0RuaitILytiWnB0c0ZFMU93TTdnN1lueHhCU3I1TEMza2pETGZMYXhnRzdJ?= =?utf-8?B?cmhacGVFdURpUlJmMExtRE9TQnJKTFVON2F2ck1jZWN4QmZKd0NVL1JBWkda?= =?utf-8?B?OFMyUDd6NDNLZ3FVUGtsZEtyRkZDanJ0Y1ZVc3dLdDhXOVBWN21yNGYxOVBl?= =?utf-8?B?UHBpNFZBQ2NnWU05MENRN09sdVdqV1c2cGczSkRjbmtFdWtTSUUzaEsyOWpU?= =?utf-8?B?Z3prZmhEMWJIWGI5cTdPcWJQR0ZwNWtzaXpGQWFGaTh1RG43T3E0c1Fyd1Uv?= =?utf-8?B?MG5xQzNkVXArcjBiUDN4Rk1ZM2UvaGlxbk5CUVRQL29qcnBLTXpPcGVrNDl5?= =?utf-8?B?SkZmK0tGeHVIby9oeEh3VER4VERpNTZaWWFKbFk2eUtJUTlNQVg5eGUvNUhi?= =?utf-8?B?ZjNpKzNJWjRiZk83akVHQzJ4TituZWJLVy9YbldmdmdPeEdUS2JJTHY1Z1Fm?= =?utf-8?B?TzMxTXNnWjF1NWZXckFLWmxaR1BWMnhDcExWMUNCYzBoemhnZUhYckYzNmE0?= =?utf-8?B?ckNVTHRFL0k5UEhYUTFORlY1UmFYYkZZNUdjcVlSQnRsWWRZZFJIa1IwYlRO?= =?utf-8?B?UFpRNVIzWU9BeHp1dDNKTkhPZ0tmVFJYdzBsUVlsNnJYZ3FPdmpVd0lJV09T?= =?utf-8?B?ODAyZ3NNZlorK1huMHRGWjRjYiszZzVPUkwyamFLZ2ViM3liREZJRnVNR0s0?= =?utf-8?B?dmN0YmlvVVFSdFVnQ090c0Npc2VQMkpQcmVVRHUzMnU5R2lvL3RlQ3NWeHdU?= =?utf-8?B?S2UvenFLWEFVY1RxVGF1NzJuSUxkY3NPQ2dZSEttWnBCdktVYys4UEtKbE9m?= =?utf-8?B?NlpDeDJkT2Z4N0tOWEtTLy90bjU4ZVJCNHhPWXFSQ3IxT1pxT0k3UjloN1R5?= =?utf-8?B?TmVEN1BaT2xUVW0wZGFuTzhUMmI2eHp3RkhTTCtJWCtiRCtrYlcwZzNhWDRq?= =?utf-8?B?NXo3dVdMTHlRa0pjQnhjNm1nOFh2L3FqWTNSc2JINytMV0YzR0dGQzFjdFJ3?= =?utf-8?B?ZGMvcVBlaER2ZGYxTFE5QzNIU2RCZ0tEUzhCU2laOE93ZndFOFF5a1J3UlQ1?= =?utf-8?B?c05FMENHY3A0a3RGVW0vdWZORWEweXFwU083VWp0VmMxeEN0WGVmUVhoNnFC?= =?utf-8?B?QXoxb3NsbnVIZXVsZHVJT1RLVWx0NFpnc1FVTHdwSXBRS2c3cEJTdzk1RE5X?= =?utf-8?B?bkUwSThoNUQxY3hrdU5TMmJZVHAra3hFcHFzSDBGdTd1RlZNTVJyR2hSaUYr?= =?utf-8?B?NVFJdlVFeW5INllnem9GaDZRR3BPTy81SjFSZzhDbERnVC9DeFphaENUYnhQ?= =?utf-8?Q?WZLweNpr8II7fMB+MM=3D?= X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 797d8763-8175-40e8-8355-08da8afc166b X-MS-Exchange-CrossTenant-AuthSource: GV1P250MB0737.EURP250.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 31 Aug 2022 02:54:14.0757 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: AS8P250MB0379 Subject: Re: [FFmpeg-devel] [PATCH v3 2/3] lavf/dashdec: Multithreaded DASH initialization X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: Lukas Fellechner: > This patch adds an "init-threads" option, specifying the max > number of threads to use. Multiple worker threads are spun up > to massively bring down init times. > --- > libavformat/dashdec.c | 351 +++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 350 insertions(+), 1 deletion(-) > > diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c > index e82da45e43..20f2557ea3 100644 > --- a/libavformat/dashdec.c > +++ b/libavformat/dashdec.c > @@ -24,6 +24,7 @@ > #include "libavutil/opt.h" > #include "libavutil/time.h" > #include "libavutil/parseutils.h" > +#include "libavutil/thread.h" > #include "internal.h" > #include "avio_internal.h" > #include "dash.h" > @@ -152,6 +153,8 @@ typedef struct DASHContext { > int max_url_size; > char *cenc_decryption_key; > > + int init_threads; > + > /* Flags for init section*/ > int is_init_section_common_video; > int is_init_section_common_audio; > @@ -2033,6 +2036,331 @@ static void move_metadata(AVStream *st, const char *key, char **value) > } > } > > +#if HAVE_THREADS > + > +struct work_pool_data > +{ > + AVFormatContext *ctx; > + struct representation *pls; > + struct representation *common_pls; > + pthread_mutex_t *common_mutex; > + pthread_cond_t *common_condition; > + int is_common; > + int is_started; > + int result; > +}; > + > +struct thread_data This is against our naming conventions: CamelCase for struct tags and typedefs, lowercase names with underscore for variable names. > +{ > + pthread_t thread; > + pthread_mutex_t *mutex; > + struct work_pool_data *work_pool; > + int work_pool_size; > + int is_started; > + int has_error; > +}; > + > +static void *worker_thread(void *ptr) > +{ > + int ret = 0; > + int i; > + struct thread_data *thread_data = (struct thread_data*)ptr; > + struct work_pool_data *work_pool = NULL; > + struct work_pool_data *data = NULL; > + for (;;) { > + > + // get next work item unless there was an error > + pthread_mutex_lock(thread_data->mutex); > + data = NULL; > + if (!thread_data->has_error) { > + work_pool = thread_data->work_pool; > + for (i = 0; i < thread_data->work_pool_size; i++) { > + if (!work_pool->is_started) { > + data = work_pool; > + data->is_started = 1; > + break; > + } > + work_pool++; > + } > + } > + pthread_mutex_unlock(thread_data->mutex); > + > + if (!data) { > + // no more work to do > + return NULL; > + } > + > + // if we are common section provider, init and signal > + if (data->is_common) { > + data->pls->parent = data->ctx; > + ret = update_init_section(data->pls); > + if (ret < 0) { > + pthread_cond_signal(data->common_condition); > + goto end; > + } > + else > + ret = AVERROR(pthread_cond_signal(data->common_condition)); > + } > + > + // if we depend on common section provider, wait for signal and copy > + if (data->common_pls) { > + ret = AVERROR(pthread_cond_wait(data->common_condition, data->common_mutex)); > + if (ret < 0) > + goto end; > + > + if (!data->common_pls->init_sec_buf) { > + goto end; > + ret = AVERROR(EFAULT); > + } > + > + ret = copy_init_section(data->pls, data->common_pls); > + if (ret < 0) > + goto end; > + } > + > + ret = begin_open_demux_for_component(data->ctx, data->pls); > + if (ret < 0) > + goto end; > + > + end: > + data->result = ret; > + > + // notify error to other threads and exit > + if (ret < 0) { > + pthread_mutex_lock(thread_data->mutex); > + thread_data->has_error = 1; > + pthread_mutex_unlock(thread_data->mutex); > + return NULL; > + } > + } > + > + > + return NULL; > +} > + > +static void create_work_pool_data(AVFormatContext *ctx, int stream_index, > + struct representation *pls, struct representation *common_pls, > + struct work_pool_data *init_data, pthread_mutex_t *common_mutex, > + pthread_cond_t *common_condition) > +{ > + init_data->ctx = ctx; > + init_data->pls = pls; > + init_data->pls->stream_index = stream_index; > + init_data->common_condition = common_condition; > + init_data->common_mutex = common_mutex; > + init_data->result = -1; > + > + if (pls == common_pls) { > + init_data->is_common = 1; > + } > + else if (common_pls) { > + init_data->common_pls = common_pls; > + } > +} > + > +static int start_thread(struct thread_data *thread_data, > + struct work_pool_data *work_pool, int work_pool_size, pthread_mutex_t *mutex) > +{ > + int ret; > + > + thread_data->mutex = mutex; > + thread_data->work_pool = work_pool; > + thread_data->work_pool_size = work_pool_size; > + > + ret = AVERROR(pthread_create(&thread_data->thread, NULL, worker_thread, (void*)thread_data)); > + if (ret == 0) > + thread_data->is_started = 1; > + > + return ret; > +} > + > +static int init_streams_multithreaded(AVFormatContext *s, int nstreams, int threads) > +{ > + DASHContext *c = s->priv_data; > + int ret = 0; > + int stream_index = 0; > + int i; We allow "for (int i = 0;" > + > + // alloc data > + struct work_pool_data *init_data = (struct work_pool_data*)av_mallocz(sizeof(struct work_pool_data) * nstreams); > + if (!init_data) > + return AVERROR(ENOMEM); > + > + struct thread_data *thread_data = (struct thread_data*)av_mallocz(sizeof(struct thread_data) * threads); > + if (!thread_data) > + return AVERROR(ENOMEM); 1. init_data leaks here on error. 2. In fact, it seems to me that both init_data and thread_data are nowhere freed. > + > + // alloc mutex and conditions > + pthread_mutex_t work_pool_mutex; > + > + pthread_mutex_t common_video_mutex; > + pthread_cond_t common_video_cond; > + > + pthread_mutex_t common_audio_mutex; > + pthread_cond_t common_audio_cond; > + > + pthread_mutex_t common_subtitle_mutex; > + pthread_cond_t common_subtitle_cond; > + > + // init mutex and conditions > + ret = AVERROR(pthread_mutex_init(&work_pool_mutex, NULL)); > + if (ret < 0) > + goto cleanup; > + > + if (c->is_init_section_common_video) { > + ret = AVERROR(pthread_mutex_init(&common_video_mutex, NULL)); > + if (ret < 0) > + goto cleanup; > + > + ret = AVERROR(pthread_cond_init(&common_video_cond, NULL)); > + if (ret < 0) > + goto cleanup; > + } > + > + if (c->is_init_section_common_audio) { > + ret = AVERROR(pthread_mutex_init(&common_audio_mutex, NULL)); > + if (ret < 0) > + goto cleanup; > + > + ret = AVERROR(pthread_cond_init(&common_audio_cond, NULL)); > + if (ret < 0) > + goto cleanup; > + } > + > + if (c->is_init_section_common_subtitle) { > + ret = AVERROR(pthread_mutex_init(&common_subtitle_mutex, NULL)); > + if (ret < 0) > + goto cleanup; > + > + ret = AVERROR(pthread_cond_init(&common_subtitle_cond, NULL)); > + if (ret < 0) > + goto cleanup; > + } > + > + // init work pool data > + struct work_pool_data* current_data = init_data; > + > + for (i = 0; i < c->n_videos; i++) { > + create_work_pool_data(s, stream_index, c->videos[i], > + c->is_init_section_common_video ? c->videos[0] : NULL, > + current_data, &common_video_mutex, &common_video_cond); > + > + stream_index++; > + current_data++; > + } > + > + for (i = 0; i < c->n_audios; i++) { > + create_work_pool_data(s, stream_index, c->audios[i], > + c->is_init_section_common_audio ? c->audios[0] : NULL, > + current_data, &common_audio_mutex, &common_audio_cond); > + > + stream_index++; > + current_data++; > + } > + > + for (i = 0; i < c->n_subtitles; i++) { > + create_work_pool_data(s, stream_index, c->subtitles[i], > + c->is_init_section_common_subtitle ? c->subtitles[0] : NULL, > + current_data, &common_subtitle_mutex, &common_subtitle_cond); > + > + stream_index++; > + current_data++; > + } This is very repetitive. > + > + // start threads > + struct thread_data *current_thread = thread_data; > + for (i = 0; i < threads; i++) { > + ret = start_thread(current_thread, init_data, nstreams, &work_pool_mutex); > + if (ret < 0) > + goto cleanup; > + > + current_thread++; > + } > + > +cleanup: > + // we need to cleanup even in case of errors, so we need to store results of init, run and cleanup > + int initResult = ret; > + int runResult = 0; > + int cleanupResult = 0; > + > + // join threads > + current_thread = thread_data; > + for (i = 0; i < threads; i++) { > + if (current_thread->is_started) { > + ret = AVERROR(pthread_join(current_thread->thread, NULL)); > + if (ret < 0) > + cleanupResult = ret; > + } > + current_thread++; > + } > + > + // finalize streams and collect results > + current_data = init_data; > + for (i = 0; i < nstreams; i++) { > + if (current_data->result < 0) { > + // thread ran into error: collect result and break > + runResult = current_data->result; > + break; > + } > + else { > + // thread success: create streams on AVFormatContext > + ret = end_open_demux_for_component(s, current_data->pls); > + if (ret < 0) > + runResult = ret; > + } > + current_data++; > + } > + > + // cleanup mutex and conditions > + ret = AVERROR(pthread_mutex_destroy(&work_pool_mutex)); > + if (ret < 0) > + cleanupResult = ret; > + > + if (c->is_init_section_common_video) { > + ret = AVERROR(pthread_mutex_destroy(&common_video_mutex)); > + if (ret < 0) > + cleanupResult = ret; > + > + ret = AVERROR(pthread_cond_destroy(&common_video_cond)); > + if (ret < 0) > + cleanupResult = ret; > + } > + > + if (c->is_init_section_common_audio) { > + ret = AVERROR(pthread_mutex_destroy(&common_audio_mutex)); > + if (ret < 0) > + cleanupResult = ret; > + > + ret = AVERROR(pthread_cond_destroy(&common_audio_cond)); > + if (ret < 0) > + cleanupResult = ret; > + } > + > + if (c->is_init_section_common_subtitle) { > + ret = AVERROR(pthread_mutex_destroy(&common_subtitle_mutex)); > + if (ret < 0) > + cleanupResult = ret; > + > + ret = AVERROR(pthread_cond_destroy(&common_subtitle_cond)); > + if (ret < 0) > + cleanupResult = ret; > + } > + > + // return results if errors have occured in one of the phases > + if (initResult < 0) > + return initResult; > + > + if (runResult < 0) > + return runResult; > + > + if (cleanupResult < 0) > + return cleanupResult; > + > + return 0; > +} > + > +#endif > + > static int dash_read_header(AVFormatContext *s) > { > DASHContext *c = s->priv_data; > @@ -2067,6 +2395,23 @@ static int dash_read_header(AVFormatContext *s) > if (c->n_subtitles) > c->is_init_section_common_subtitle = is_common_init_section_exist(c->subtitles, c->n_subtitles); > > + int threads = 0; > + int nstreams = c->n_videos + c->n_audios + c->n_subtitles; > + > +#if HAVE_THREADS > + threads = FFMIN(nstreams, c->init_threads); > +#endif > + > + if (threads > 1) > + { > +#if HAVE_THREADS > + ret = init_streams_multithreaded(s, nstreams, threads); > + if (ret < 0) > + return ret; > +#endif > + } > + else > + { > /* Open the demuxer for video and audio components if available */ > for (i = 0; i < c->n_videos; i++) { > rep = c->videos[i]; > @@ -2115,6 +2460,7 @@ static int dash_read_header(AVFormatContext *s) > > if (!stream_index) > return AVERROR_INVALIDDATA; > + } > > /* Create a program */ > program = av_new_program(s, 0); > @@ -2366,7 +2712,10 @@ static const AVOption dash_options[] = { > OFFSET(allowed_extensions), AV_OPT_TYPE_STRING, > {.str = "aac,m4a,m4s,m4v,mov,mp4,webm,ts"}, > INT_MIN, INT_MAX, FLAGS}, > - { "cenc_decryption_key", "Media decryption key (hex)", OFFSET(cenc_decryption_key), AV_OPT_TYPE_STRING, {.str = NULL}, INT_MIN, INT_MAX, .flags = FLAGS }, > + { "cenc_decryption_key", "Media decryption key (hex)", OFFSET(cenc_decryption_key), > + AV_OPT_TYPE_STRING, {.str = NULL}, INT_MIN, INT_MAX, .flags = FLAGS }, > + { "init_threads", "Number of threads to use for initializing the DASH stream", > + OFFSET(init_threads), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 64, FLAGS }, > {NULL} > }; > > -- > 2.31.1.windows.1 > 1. We actually have an API to process multiple tasks by different threads: Look at libavutil/slicethread.h. Why can't you reuse that? 2. In case initialization of one of the conditions/mutexes fails, you are nevertheless destroying them; you are even destroying completely uninitialized mutexes. This is undefined behaviour. Checking the result of it does not fix this. - Andreas _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".