static void test_media_preparsed(const char** argv, int argc) { // We use this image file because "empty.voc" has no track. const char * file = SRCDIR"/samples/image.jpg"; log ("Testing set_media\n"); libvlc_instance_t *vlc = libvlc_new (argc, argv); assert (vlc != NULL); libvlc_media_t *media = libvlc_media_new_path (vlc, file); assert (media != NULL); vlc_sem_t sem; vlc_sem_init (&sem, 0); // Check to see if we are properly receiving the event. libvlc_event_manager_t *em = libvlc_media_event_manager (media); libvlc_event_attach (em, libvlc_MediaParsedChanged, preparsed_changed, &sem); // Parse the media. This is synchronous. libvlc_media_parse_async(media); // Wait for preparsed event vlc_sem_wait (&sem); vlc_sem_destroy (&sem); // We are good, now check Elementary Stream info. libvlc_media_track_t **tracks; unsigned nb_tracks = libvlc_media_tracks_get (media, &tracks); assert (nb_tracks == 1); assert (tracks[0]->i_type == libvlc_track_video); libvlc_media_tracks_release (tracks, nb_tracks); libvlc_media_release (media); libvlc_release (vlc); }
jobjectArray read_track_info_internal(JNIEnv *env, jobject thiz, libvlc_media_t* p_m) { /* get java class */ jclass cls = (*env)->FindClass( env, "org/videolan/libvlc/TrackInfo" ); if ( !cls ) { LOGE("Failed to load class (org/videolan/libvlc/TrackInfo)" ); return NULL; } /* get java class contructor */ jmethodID clsCtor = (*env)->GetMethodID( env, cls, "<init>", "()V" ); if ( !clsCtor ) { LOGE("Failed to find class constructor (org/videolan/libvlc/TrackInfo)" ); return NULL; } /* Get the tracks information of the media. */ libvlc_media_track_t **p_tracks; int i_nbTracks = libvlc_media_tracks_get(p_m, &p_tracks); jobjectArray array = (*env)->NewObjectArray(env, i_nbTracks + 1, cls, NULL); unsigned i; if (array != NULL) { for (i = 0; i <= i_nbTracks; ++i) { jobject item = (*env)->NewObject(env, cls, clsCtor); if (item == NULL) continue; (*env)->SetObjectArrayElement(env, array, i, item); // use last track for metadata if (i == i_nbTracks) { setInt(env, item, "Type", 3 /* TYPE_META */); setLong(env, item, "Length", libvlc_media_get_duration(p_m)); setString(env, item, "Title", libvlc_media_get_meta(p_m, libvlc_meta_Title)); setString(env, item, "Artist", libvlc_media_get_meta(p_m, libvlc_meta_Artist)); setString(env, item, "Album", libvlc_media_get_meta(p_m, libvlc_meta_Album)); setString(env, item, "Genre", libvlc_media_get_meta(p_m, libvlc_meta_Genre)); setString(env, item, "ArtworkURL", libvlc_media_get_meta(p_m, libvlc_meta_ArtworkURL)); continue; } setInt(env, item, "Id", p_tracks[i]->i_id); setInt(env, item, "Type", p_tracks[i]->i_type); setString(env, item, "Codec", (const char*)vlc_fourcc_GetDescription(0,p_tracks[i]->i_codec)); setString(env, item, "Language", p_tracks[i]->psz_language); setInt(env, item, "Bitrate", p_tracks[i]->i_bitrate); if (p_tracks[i]->i_type == libvlc_track_video) { setInt(env, item, "Height", p_tracks[i]->video->i_height); setInt(env, item, "Width", p_tracks[i]->video->i_width); setFloat(env, item, "Framerate", (float)p_tracks[i]->video->i_frame_rate_num / p_tracks[i]->video->i_frame_rate_den); } if (p_tracks[i]->i_type == libvlc_track_audio) { setInt(env, item, "Channels", p_tracks[i]->audio->i_channels); setInt(env, item, "Samplerate", p_tracks[i]->audio->i_rate); } } } libvlc_media_tracks_release(p_tracks, i_nbTracks); return array; }
/** * Thumbnailer main function. * return null if the thumbail generation failed. **/ jbyteArray Java_org_videolan_libvlc_util_VLCUtil_nativeGetThumbnail(JNIEnv *env, jobject thiz, jobject jmedia, const jint frameWidth, const jint frameHeight) { vlcjni_object *p_obj = VLCJniObject_getInstance(env, jmedia); jbyteArray byteArray = NULL; /* Create the thumbnailer data structure */ thumbnailer_sys_t *sys = calloc(1, sizeof(thumbnailer_sys_t)); if (sys == NULL) { LOGE("Could not create the thumbnailer data structure!"); goto enomem; } /* Initialize the barrier. */ pthread_mutex_init(&sys->doneMutex, NULL); pthread_cond_init(&sys->doneCondVar, NULL); /* Create a media player playing environment */ libvlc_media_player_t *mp = libvlc_media_player_new_from_media(p_obj->u.p_m); libvlc_media_player_set_video_title_display(mp, libvlc_position_disable, 0); /* Get the size of the video with the tracks information of the media. */ libvlc_media_track_t **tracks; libvlc_media_parse(p_obj->u.p_m); int nbTracks = libvlc_media_tracks_get(p_obj->u.p_m, &tracks); /* Parse the results */ unsigned videoWidth = 0, videoHeight = 0; bool hasVideoTrack = false; for (unsigned i = 0; i < nbTracks; ++i) if (tracks[i]->i_type == libvlc_track_video) { videoWidth = tracks[i]->video->i_width; videoHeight = tracks[i]->video->i_height; hasVideoTrack = true; break; } libvlc_media_tracks_release(tracks, nbTracks); /* Abort if we have not found a video track. */ if (!hasVideoTrack) { LOGE("Could not find any video track in this file.\n"); goto end; } LOGD("Video dimensions: %ix%i.\n", videoWidth, videoHeight ); /* VLC could not tell us the size */ if( videoWidth == 0 || videoHeight == 0 ) { LOGE("Could not find the video dimensions.\n"); goto end; } if( videoWidth < THUMBNAIL_MIN_WIDTH || videoHeight < THUMBNAIL_MIN_HEIGHT || videoWidth > THUMBNAIL_MAX_WIDTH || videoHeight > THUMBNAIL_MAX_HEIGHT ) { LOGE("Wrong video dimensions.\n"); goto end; } /* Compute the size parameters of the frame to generate. */ unsigned thumbWidth = frameWidth; unsigned thumbHeight = frameHeight; const float inputAR = (float)videoWidth / videoHeight; const float screenAR = (float)frameWidth / frameHeight; /* Most of the cases, video is wider than tall */ if (screenAR < inputAR) { thumbHeight = (float)frameWidth / inputAR + 1; sys->blackBorders = ( (frameHeight - thumbHeight) / 2 ) * frameWidth; } else { LOGD("Weird aspect Ratio.\n"); thumbWidth = (float)frameHeight * inputAR; sys->blackBorders = (frameWidth - thumbWidth) / 2; } sys->thumbPitch = thumbWidth * PIXEL_SIZE; sys->thumbHeight = thumbHeight; sys->frameWidth = frameWidth; /* Allocate the memory to store the frames. */ size_t thumbSize = sys->thumbPitch * (sys->thumbHeight+1); sys->thumbData = malloc(thumbSize); if (sys->thumbData == NULL) { LOGE("Could not allocate the memory to store the frame!"); goto end; } /* Allocate the memory to store the thumbnail. */ unsigned frameSize = frameWidth * frameHeight * PIXEL_SIZE; sys->frameData = calloc(frameSize, 1); if (sys->frameData == NULL) { LOGE("Could not allocate the memory to store the thumbnail!"); goto end; } /* Set the video format and the callbacks. */ libvlc_video_set_format(mp, "RGBA", thumbWidth, thumbHeight, sys->thumbPitch); libvlc_video_set_callbacks(mp, thumbnailer_lock, thumbnailer_unlock, NULL, (void*)sys); sys->state = THUMB_SEEKING; /* Play the media. */ libvlc_media_player_play(mp); libvlc_media_player_set_position(mp, THUMBNAIL_POSITION); const int wait_time = 50000; const int max_attempts = 100; for (int i = 0; i < max_attempts; ++i) { if (libvlc_media_player_is_playing(mp) && libvlc_media_player_get_position(mp) >= THUMBNAIL_POSITION) break; usleep(wait_time); } /* Wait for the thumbnail to be generated. */ pthread_mutex_lock(&sys->doneMutex); sys->state = THUMB_SEEKED; struct timespec deadline; clock_gettime(CLOCK_REALTIME, &deadline); deadline.tv_sec += 10; /* amount of seconds before we abort thumbnailer */ do { int ret = pthread_cond_timedwait(&sys->doneCondVar, &sys->doneMutex, &deadline); if (ret == ETIMEDOUT) break; } while (sys->state != THUMB_DONE); pthread_mutex_unlock(&sys->doneMutex); /* Stop and release the media player. */ libvlc_media_player_stop(mp); libvlc_media_player_release(mp); if (sys->state == THUMB_DONE) { /* Create the Java byte array to return the create thumbnail. */ byteArray = (*env)->NewByteArray(env, frameSize); if (byteArray == NULL) { LOGE("Could not allocate the Java byte array to store the frame!"); goto end; } (*env)->SetByteArrayRegion(env, byteArray, 0, frameSize, (jbyte *)sys->frameData); } end: pthread_mutex_destroy(&sys->doneMutex); pthread_cond_destroy(&sys->doneCondVar); free(sys->frameData); free(sys->thumbData); free(sys); enomem: return byteArray; }
unsigned libvlc_media_tracks_get( libvlc_media_t *p_md, libvlc_media_track_t *** pp_es ) { assert( p_md ); input_item_t *p_input_item = p_md->p_input_item; vlc_mutex_lock( &p_input_item->lock ); const int i_es = p_input_item->i_es; *pp_es = (i_es > 0) ? calloc( i_es, sizeof(**pp_es) ) : NULL; if( !*pp_es ) /* no ES, or OOM */ { vlc_mutex_unlock( &p_input_item->lock ); return 0; } /* Fill array */ for( int i = 0; i < i_es; i++ ) { libvlc_media_track_t *p_mes = calloc( 1, sizeof(*p_mes) ); if ( p_mes ) { p_mes->audio = malloc( __MAX(__MAX(sizeof(*p_mes->audio), sizeof(*p_mes->video)), sizeof(*p_mes->subtitle)) ); } if ( !p_mes || !p_mes->audio ) { libvlc_media_tracks_release( *pp_es, i_es ); *pp_es = NULL; free( p_mes ); vlc_mutex_unlock( &p_input_item->lock ); return 0; } (*pp_es)[i] = p_mes; const es_format_t *p_es = p_input_item->es[i]; p_mes->i_codec = p_es->i_codec; p_mes->i_original_fourcc = p_es->i_original_fourcc; p_mes->i_id = p_es->i_id; p_mes->i_profile = p_es->i_profile; p_mes->i_level = p_es->i_level; p_mes->i_bitrate = p_es->i_bitrate; p_mes->psz_language = p_es->psz_language != NULL ? strdup(p_es->psz_language) : NULL; p_mes->psz_description = p_es->psz_description != NULL ? strdup(p_es->psz_description) : NULL; switch(p_es->i_cat) { case UNKNOWN_ES: default: p_mes->i_type = libvlc_track_unknown; break; case VIDEO_ES: p_mes->i_type = libvlc_track_video; p_mes->video->i_height = p_es->video.i_height; p_mes->video->i_width = p_es->video.i_width; p_mes->video->i_sar_num = p_es->video.i_sar_num; p_mes->video->i_sar_den = p_es->video.i_sar_den; p_mes->video->i_frame_rate_num = p_es->video.i_frame_rate; p_mes->video->i_frame_rate_den = p_es->video.i_frame_rate_base; break; case AUDIO_ES: p_mes->i_type = libvlc_track_audio; p_mes->audio->i_channels = p_es->audio.i_channels; p_mes->audio->i_rate = p_es->audio.i_rate; break; case SPU_ES: p_mes->i_type = libvlc_track_text; p_mes->subtitle->psz_encoding = p_es->subs.psz_encoding != NULL ? strdup(p_es->subs.psz_encoding) : NULL; break; } } vlc_mutex_unlock( &p_input_item->lock ); return i_es; }
/** * Thumbnailer main function. * return null if the thumbail generation failed. **/ jbyteArray Java_org_videolan_libvlc_LibVLC_getThumbnail(JNIEnv *env, jobject thiz, jlong instance, jstring filePath, const jint frameWidth, const jint frameHeight) { libvlc_instance_t *libvlc = (libvlc_instance_t *)(intptr_t)instance; jbyteArray byteArray = NULL; /* Create the thumbnailer data structure */ thumbnailer_sys_t *sys = calloc(1, sizeof(thumbnailer_sys_t)); if (sys == NULL) { LOGE("Could not create the thumbnailer data structure!"); return NULL; } /* Initialize the barrier. */ pthread_mutex_init(&sys->doneMutex, NULL); pthread_cond_init(&sys->doneCondVar, NULL); /* Create a media player playing environment */ libvlc_media_player_t *mp = libvlc_media_player_new(libvlc); libvlc_media_t *m = new_media(instance, env, thiz, filePath, true, false); if (m == NULL) { LOGE("Could not create the media to play!"); goto end; } /* Fast and no options */ libvlc_media_add_option( m, ":no-audio" ); libvlc_media_add_option( m, ":no-spu" ); libvlc_media_add_option( m, ":no-osd" ); libvlc_media_player_set_media(mp, m); /* Get the size of the video with the tracks information of the media. */ libvlc_media_track_t **tracks; libvlc_media_parse(m); int nbTracks = libvlc_media_tracks_get(m, &tracks); libvlc_media_release(m); /* Parse the results */ unsigned videoWidth = 0, videoHeight = 0; bool hasVideoTrack = false; for (unsigned i = 0; i < nbTracks; ++i) if (tracks[i]->i_type == libvlc_track_video) { videoWidth = tracks[i]->video->i_width; videoHeight = tracks[i]->video->i_height; hasVideoTrack = true; break; } libvlc_media_tracks_release(tracks, nbTracks); /* Abort if we have not found a video track. */ if (!hasVideoTrack) { LOGE("Could not find any video track in this file.\n"); goto end; } LOGD("Video dimensions: %ix%i.\n", videoWidth, videoHeight ); /* VLC could not tell us the size */ if( videoWidth == 0 || videoHeight == 0 ) { LOGE("Could not find the video dimensions.\n"); goto end; } if( videoWidth < 32 || videoHeight < 32 || videoWidth > 2048 || videoWidth > 2048 ) { LOGE("Wrong video dimensions.\n"); goto end; } /* Compute the size parameters of the frame to generate. */ unsigned thumbWidth = frameWidth; unsigned thumbHeight = frameHeight; const float inputAR = (float)videoWidth / videoHeight; const float screenAR = (float)frameWidth / frameHeight; /* Most of the cases, video is wider than tall */ if (screenAR < inputAR) { thumbHeight = (float)frameWidth / inputAR + 1; sys->blackBorders = ( (frameHeight - thumbHeight) / 2 ) * frameWidth; } else { LOGD("Weird aspect Ratio.\n"); thumbWidth = (float)frameHeight * inputAR; sys->blackBorders = (frameWidth - thumbWidth) / 2; } sys->thumbPitch = thumbWidth * PIXEL_SIZE; sys->thumbHeight = thumbHeight; sys->frameWidth = frameWidth; /* Allocate the memory to store the frames. */ size_t thumbSize = sys->thumbPitch * (sys->thumbHeight+1); sys->thumbData = malloc(thumbSize); if (sys->thumbData == NULL) { LOGE("Could not allocate the memory to store the frame!"); goto end; } /* Allocate the memory to store the thumbnail. */ unsigned frameSize = frameWidth * frameHeight * PIXEL_SIZE; sys->frameData = calloc(frameSize, 1); if (sys->frameData == NULL) { LOGE("Could not allocate the memory to store the thumbnail!"); goto end; } /* Set the video format and the callbacks. */ libvlc_video_set_format(mp, "RGBA", thumbWidth, thumbHeight, sys->thumbPitch); libvlc_video_set_callbacks(mp, thumbnailer_lock, thumbnailer_unlock, NULL, (void*)sys); sys->state = THUMB_SEEKING; /* Play the media. */ libvlc_media_player_play(mp); libvlc_media_player_set_position(mp, THUMBNAIL_POSITION); int loops = 100; for (;;) { float pos = libvlc_media_player_get_position(mp); if (pos > THUMBNAIL_POSITION || !loops--) break; usleep(50000); } /* Wait for the thumbnail to be generated. */ pthread_mutex_lock(&sys->doneMutex); sys->state = THUMB_SEEKED; struct timespec deadline; clock_gettime(CLOCK_REALTIME, &deadline); deadline.tv_sec += 10; /* amount of seconds before we abort thumbnailer */ do { int ret = pthread_cond_timedwait(&sys->doneCondVar, &sys->doneMutex, &deadline); if (ret == ETIMEDOUT) break; } while (sys->state != THUMB_DONE); pthread_mutex_unlock(&sys->doneMutex); /* Stop and release the media player. */ libvlc_media_player_stop(mp); libvlc_media_player_release(mp); if (sys->state == THUMB_DONE) { /* Create the Java byte array to return the create thumbnail. */ byteArray = (*env)->NewByteArray(env, frameSize); if (byteArray == NULL) { LOGE("Could not allocate the Java byte array to store the frame!"); goto end; } (*env)->SetByteArrayRegion(env, byteArray, 0, frameSize, (jbyte *)sys->frameData); } end: pthread_mutex_destroy(&sys->doneMutex); pthread_cond_destroy(&sys->doneCondVar); free(sys->frameData); free(sys->thumbData); free(sys); return byteArray; }