/************************************************************************ * hb_thread_init() ************************************************************************ * name: user-friendly name * function: the thread routine * arg: argument of the routine * priority: HB_LOW_PRIORITY or HB_NORMAL_PRIORITY ***********************************************************************/ hb_thread_t * hb_thread_init( char * name, void (* function)(void *), void * arg, int priority ) { hb_thread_t * t = calloc( sizeof( hb_thread_t ), 1 ); t->name = strdup( name ); t->function = function; t->arg = arg; t->priority = priority; t->lock = hb_lock_init(); /* Create and start the thread */ #if defined( SYS_BEOS ) t->thread = spawn_thread( (thread_func) hb_thread_func, name, priority, t ); resume_thread( t->thread ); #elif USE_PTHREAD pthread_create( &t->thread, NULL, (void * (*)( void * )) hb_thread_func, t ); //#elif defined( SYS_CYGWIN ) // t->thread = CreateThread( NULL, 0, // (LPTHREAD_START_ROUTINE) hb_thread_func, t, 0, NULL ); // // /* Maybe use THREAD_PRIORITY_LOWEST instead */ // if( priority == HB_LOW_PRIORITY ) // SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL ); #endif hb_deep_log( 2, "thread %"PRIx64" started (\"%s\")", hb_thread_to_integer( t ), t->name ); return t; }
static int hb_qsv_filter_pre_init( hb_filter_object_t * filter, hb_filter_init_t * init ){ filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) ); hb_filter_private_t * pv = filter->private_data; pv->job = init->job; pv->pre.frame_go = 0; pv->pre.frame_completed = hb_cond_init(); pv->pre.frame_completed_lock = hb_lock_init(); pv->post.frame_go = 0; pv->post.frame_completed = hb_cond_init(); pv->post.frame_completed_lock = hb_lock_init(); pv->pre_busy.frame_go = 0; pv->pre_busy.frame_completed = hb_cond_init(); pv->pre_busy.frame_completed_lock = hb_lock_init(); pv->post_busy.frame_go = 0; pv->post_busy.frame_completed = hb_cond_init(); pv->post_busy.frame_completed_lock = hb_lock_init(); pv->list = hb_list_init(); // just to remind: // PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) , 3 planes: Y, U, V // PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) pv->sws_context_from_nv12 = hb_sws_get_context( pv->job->title->geometry.width, pv->job->title->geometry.height, AV_PIX_FMT_NV12, pv->job->title->geometry.width, pv->job->title->geometry.height, AV_PIX_FMT_YUV420P, SWS_LANCZOS|SWS_ACCURATE_RND); pv->sws_context_to_nv12 = hb_sws_get_context( pv->job->title->geometry.width, pv->job->title->geometry.height, AV_PIX_FMT_YUV420P, pv->job->title->geometry.width, pv->job->title->geometry.height, AV_PIX_FMT_NV12, SWS_LANCZOS|SWS_ACCURATE_RND); return 0; }
hb_fifo_t * hb_fifo_init( int capacity, int thresh ) { hb_fifo_t * f; f = calloc( sizeof( hb_fifo_t ), 1 ); f->lock = hb_lock_init(); f->cond_full = hb_cond_init(); f->cond_empty = hb_cond_init(); f->capacity = capacity; f->thresh = thresh; f->buffer_size = 0; return f; }
void hb_buffer_pool_init( void ) { buffers.lock = hb_lock_init(); buffers.allocated = 0; /* we allocate pools for sizes 2^10 through 2^25. requests larger than * 2^25 will get passed through to malloc. */ int i; for ( i = 10; i < 26; ++i ) { buffers.pool[i] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS, 1); buffers.pool[i]->buffer_size = 1 << i; } /* requests smaller than 2^10 are satisfied from the 2^10 pool. */ for ( i = 1; i < 10; ++i ) { buffers.pool[i] = buffers.pool[10]; } }
/*********************************************************************** * hb_work_sync_init *********************************************************************** * Initialize the work object **********************************************************************/ hb_work_object_t * hb_sync_init( hb_job_t * job ) { hb_title_t * title = job->title; hb_chapter_t * chapter; int i; uint64_t duration; hb_work_private_t * pv; hb_sync_video_t * sync; hb_work_object_t * w; hb_work_object_t * ret = NULL; pv = calloc( 1, sizeof( hb_work_private_t ) ); sync = &pv->type.video; pv->common = calloc( 1, sizeof( hb_sync_common_t ) ); pv->common->ref++; pv->common->mutex = hb_lock_init(); pv->common->audio_pts_thresh = -1; pv->common->next_frame = hb_cond_init(); pv->common->pts_count = 1; if ( job->frame_to_start || job->pts_to_start ) { pv->common->start_found = 0; } else { pv->common->start_found = 1; } ret = w = hb_get_work( WORK_SYNC_VIDEO ); w->private_data = pv; w->fifo_in = job->fifo_raw; // When doing subtitle indepth scan, the pipeline ends at sync if ( !job->indepth_scan ) w->fifo_out = job->fifo_sync; else w->fifo_out = NULL; pv->job = job; pv->common->pts_offset = INT64_MIN; sync->first_frame = 1; if( job->pass == 2 ) { /* We already have an accurate frame count from pass 1 */ hb_interjob_t * interjob = hb_interjob_get( job->h ); sync->count_frames_max = interjob->frame_count; } else { /* Calculate how many video frames we are expecting */ if ( job->pts_to_stop ) { duration = job->pts_to_stop + 90000; } else if( job->frame_to_stop ) { /* Set the duration to a rough estimate */ duration = ( job->frame_to_stop / ( title->rate / title->rate_base ) ) * 90000; } else { duration = 0; for( i = job->chapter_start; i <= job->chapter_end; i++ ) { chapter = hb_list_item( job->list_chapter, i - 1 ); duration += chapter->duration; } } sync->count_frames_max = duration * title->rate / title->rate_base / 90000; } hb_log( "sync: expecting %d video frames", sync->count_frames_max ); /* Initialize libsamplerate for every audio track we have */ if ( ! job->indepth_scan ) { for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { InitAudio( job, pv->common, i ); } } pv->common->first_pts = malloc( sizeof(int64_t) * pv->common->pts_count ); for ( i = 0; i < pv->common->pts_count; i++ ) pv->common->first_pts[i] = INT64_MAX; return ret; }
hb_work_object_t * hb_muxer_init( hb_job_t * job ) { hb_title_t * title = job->title; int i; hb_mux_t * mux = calloc( sizeof( hb_mux_t ), 1 ); hb_work_object_t * w; hb_work_object_t * muxer; mux->mutex = hb_lock_init(); // set up to interleave track data in blocks of 1 video frame time. // (the best case for buffering and playout latency). The container- // specific muxers can reblock this into bigger chunks if necessary. mux->interleave = 90000. * (double)job->vrate_base / (double)job->vrate; mux->pts = mux->interleave; /* Get a real muxer */ if( job->pass == 0 || job->pass == 2) { switch( job->mux ) { case HB_MUX_MP4: mux->m = hb_mux_mp4_init( job ); break; case HB_MUX_MKV: mux->m = hb_mux_mkv_init( job ); break; default: hb_error( "No muxer selected, exiting" ); *job->die = 1; return NULL; } /* Create file, write headers */ if( mux->m ) { mux->m->init( mux->m ); } } /* Initialize the work objects that will receive fifo data */ muxer = hb_get_work( WORK_MUX ); muxer->private_data = calloc( sizeof( hb_work_private_t ), 1 ); muxer->private_data->job = job; muxer->private_data->mux = mux; mux->ref++; muxer->private_data->track = mux->ntracks; muxer->fifo_in = job->fifo_mpeg4; add_mux_track( mux, job->mux_data, 1 ); muxer->done = &muxer->private_data->mux->done; for( i = 0; i < hb_list_count( title->list_audio ); i++ ) { hb_audio_t *audio = hb_list_item( title->list_audio, i ); w = hb_get_work( WORK_MUX ); w->private_data = calloc( sizeof( hb_work_private_t ), 1 ); w->private_data->job = job; w->private_data->mux = mux; mux->ref++; w->private_data->track = mux->ntracks; w->fifo_in = audio->priv.fifo_out; add_mux_track( mux, audio->priv.mux_data, 1 ); w->done = &job->done; hb_list_add( job->list_work, w ); w->thread = hb_thread_init( w->name, mux_loop, w, HB_NORMAL_PRIORITY ); } for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) { hb_subtitle_t *subtitle = hb_list_item( title->list_subtitle, i ); if (subtitle->config.dest != PASSTHRUSUB) continue; w = hb_get_work( WORK_MUX ); w->private_data = calloc( sizeof( hb_work_private_t ), 1 ); w->private_data->job = job; w->private_data->mux = mux; mux->ref++; w->private_data->track = mux->ntracks; w->fifo_in = subtitle->fifo_out; add_mux_track( mux, subtitle->mux_data, 0 ); w->done = &job->done; hb_list_add( job->list_work, w ); w->thread = hb_thread_init( w->name, mux_loop, w, HB_NORMAL_PRIORITY ); } return muxer; }
int taskset_init( taskset_t *ts, int thread_count, size_t arg_size ) { int init_step; init_step = 0; memset( ts, 0, sizeof( *ts ) ); ts->thread_count = thread_count; ts->arg_size = arg_size; ts->bitmap_elements = ( ts->thread_count + 31 ) / 32; ts->task_threads = malloc( sizeof( hb_thread_t* ) * ts->thread_count ); if( ts->task_threads == NULL ) goto fail; init_step++; if( arg_size != 0 ) { ts->task_threads_args = malloc( arg_size * ts->thread_count ); if( ts->task_threads == NULL ) goto fail; } init_step++; ts->task_begin_bitmap = malloc( sizeof( uint32_t ) * ts->bitmap_elements ); if( ts->task_begin_bitmap == NULL ) goto fail; init_step++; ts->task_complete_bitmap = malloc( sizeof( uint32_t ) * ts->bitmap_elements ); if( ts->task_complete_bitmap == NULL ) goto fail; init_step++; ts->task_stop_bitmap = malloc( sizeof( uint32_t ) * ts->bitmap_elements ); if( ts->task_stop_bitmap == NULL ) goto fail; init_step++; ts->task_cond_lock = hb_lock_init(); if( ts->task_cond_lock == NULL) goto fail; init_step++; ts->task_begin = hb_cond_init(); if( ts->task_begin == NULL) goto fail; init_step++; ts->task_complete = hb_cond_init(); if( ts->task_complete == NULL) goto fail; init_step++; /* * Initialize all arg data to 0. */ memset(ts->task_threads_args, 0, ts->arg_size * ts->thread_count ); /* * Inialize bitmaps to all bits set. This means that any unused bits * in the bitmap are already in the "condition satisfied" state allowing * us to test the bitmap 32bits at a time without having to mask off * the end. */ memset(ts->task_begin_bitmap, 0xFF, sizeof( uint32_t ) * ts->bitmap_elements ); memset(ts->task_complete_bitmap, 0xFF, sizeof( uint32_t ) * ts->bitmap_elements ); memset(ts->task_stop_bitmap, 0, sizeof( uint32_t ) * ts->bitmap_elements ); /* * Important to start off with the threads locked waiting * on input, no work completed, and not asked to stop. */ bit_nclear( ts->task_begin_bitmap, 0, ts->thread_count - 1 ); bit_nclear( ts->task_complete_bitmap, 0, ts->thread_count - 1 ); bit_nclear( ts->task_stop_bitmap, 0, ts->thread_count - 1 ); return (1); fail: switch (init_step) { default: hb_cond_close( &ts->task_complete ); /* FALL THROUGH */ case 7: hb_cond_close( &ts->task_begin ); /* FALL THROUGH */ case 6: hb_lock_close( &ts->task_cond_lock ); /* FALL THROUGH */ case 5: free( ts->task_stop_bitmap ); /* FALL THROUGH */ case 4: free( ts->task_complete_bitmap ); /* FALL THROUGH */ case 3: free( ts->task_begin_bitmap ); /* FALL THROUGH */ case 2: if( ts->task_threads_args == NULL ) free( ts->task_threads_args ); /* FALL THROUGH */ case 1: free( ts->task_threads ); /* FALL THROUGH */ case 0: break; } return (0); }
hb_filter_private_t * hb_rotate_init( int pix_fmt, int width, int height, char * settings ) { if( pix_fmt != PIX_FMT_YUV420P ) { return 0; } hb_filter_private_t * pv = calloc( 1, sizeof(struct hb_filter_private_s) ); pv->pix_fmt = pix_fmt; pv->width[0] = width; pv->height[0] = height; pv->width[1] = pv->width[2] = width >> 1; pv->height[1] = pv->height[2] = height >> 1; pv->buf_out = hb_video_buffer_init( width, height ); pv->buf_settings = hb_buffer_init( 0 ); pv->mode = MODE_DEFAULT; pv->ref_stride[0] = pv->width[0]; pv->ref_stride[1] = pv->width[1]; pv->ref_stride[2] = pv->width[2]; if( settings ) { sscanf( settings, "%d", &pv->mode ); } pv->cpu_count = hb_get_cpu_count(); /* * Create threads and locks. */ pv->rotate_threads = malloc( sizeof( hb_thread_t* ) * pv->cpu_count ); pv->rotate_begin_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count ); pv->rotate_complete_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count ); pv->rotate_arguments = malloc( sizeof( rotate_arguments_t ) * pv->cpu_count ); int i; for( i = 0; i < pv->cpu_count; i++ ) { rotate_thread_arg_t *thread_args; thread_args = malloc( sizeof( rotate_thread_arg_t ) ); if( thread_args ) { thread_args->pv = pv; thread_args->segment = i; pv->rotate_begin_lock[i] = hb_lock_init(); pv->rotate_complete_lock[i] = hb_lock_init(); /* * Important to start off with the threads locked waiting * on input. */ hb_lock( pv->rotate_begin_lock[i] ); pv->rotate_arguments[i].stop = 0; pv->rotate_arguments[i].dst = NULL; pv->rotate_threads[i] = hb_thread_init( "rotate_filter_segment", rotate_filter_thread, thread_args, HB_NORMAL_PRIORITY ); } else { hb_error( "rotate could not create threads" ); } } return pv; }