FFSampledSP
FFURLInputStream.c
Go to the documentation of this file.
1 /*
2  * =================================================
3  * Copyright 2013 tagtraum industries incorporated
4  * This file is part of FFSampledSP.
5  *
6  * FFSampledSP is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFSampledSP is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFSampledSP; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  * =================================================
20  *
21  * @author <a href="mailto:hs@tagtraum.com">Hendrik Schreiber</a>
22  */
23 
24 #include "com_tagtraum_ffsampledsp_FFURLInputStream.h"
25 #include "FFUtils.h"
26 
27 
35 JNIEXPORT void JNICALL Java_com_tagtraum_ffsampledsp_FFURLInputStream_fillNativeBuffer(JNIEnv *env, jobject stream, jlong aio_pointer) {
36 
37  FFAudioIO *aio = (FFAudioIO*)(intptr_t)aio_pointer;
38  aio->env = env;
39  aio->java_instance = stream;
40 
41  ff_fill_buffer(aio);
42  // we can ignore the return value,
43  // because all ff_fill_buffer already
44  // throws a suitable Java exception
45  // in the case of an error
46 }
47 
56 JNIEXPORT jlong JNICALL Java_com_tagtraum_ffsampledsp_FFURLInputStream_open(JNIEnv *env, jobject stream, jstring url, jint streamIndex) {
57 
58  int res = 0;
59  FFAudioIO *aio = NULL;
60 
61  // copy URL to local char*
62  const char *input_url = (*env)->GetStringUTFChars(env, url, NULL);
63  if (!input_url) {
64  res = AVERROR(ENOMEM);
65  throwIOExceptionIfError(env, res, "Failed to get url");
66  goto bail;
67  }
68 
69  aio = calloc(1, sizeof(FFAudioIO));
70  if (!aio) {
71  res = AVERROR(ENOMEM);
72  throwIOExceptionIfError(env, res, "Could not allocate audio io");
73  goto bail;
74  }
75  aio->stream_index = (int)streamIndex;
76 
77  res = ff_open_file(env, &(aio->format_context), &(aio->stream), &(aio->decode_context), &(aio->stream_index), input_url);
78  if (res) {
79  goto bail;
80  }
81  res = ff_init_audioio(env, aio);
82  if (res) {
83  goto bail;
84  }
85 
86 #ifdef DEBUG
87  fprintf(stderr, "stream->codecpar->bits_per_coded_sample: %i\n", aio->stream->codecpar->bits_per_coded_sample);
88  fprintf(stderr, "stream->codecpar->bits_per_raw_sample : %i\n", aio->stream->codecpar->bits_per_raw_sample);
89  fprintf(stderr, "stream->codecpar->bit_rate: %lli\n", aio->stream->codecpar->bit_rate);
90  fprintf(stderr, "frames : %" PRId64 "\n", aio->stream->nb_frames);
91  fprintf(stderr, "sample_rate: %i\n", aio->stream->codecpar->sample_rate);
92  fprintf(stderr, "channels : %i\n", aio->stream->codecpar->channels);
93  fprintf(stderr, "frame_size : %i\n", aio->stream->codecpar->frame_size);
94  fprintf(stderr, "codec_id : %i\n", aio->stream->codecpar->codec_id);
95 #endif
96 
97 bail:
98 
99  if (res) ff_audioio_free(aio);
100  (*env)->ReleaseStringUTFChars(env, url, input_url);
101 
102  return (jlong)(intptr_t)aio;
103 }
104 
113 JNIEXPORT jboolean JNICALL Java_com_tagtraum_ffsampledsp_FFURLInputStream_isSeekable(JNIEnv *env, jobject stream, jlong aio_pointer) {
114  FFAudioIO *aio = (FFAudioIO*)(intptr_t)aio_pointer;
115  jboolean seekable = JNI_FALSE;
116  seekable = aio->format_context->pb->seekable != 0;
117  return seekable;
118 }
119 
128 JNIEXPORT void JNICALL Java_com_tagtraum_ffsampledsp_FFURLInputStream_seek(JNIEnv *env, jobject stream, jlong aio_pointer, jlong microseconds) {
129  FFAudioIO *aio = (FFAudioIO*)(intptr_t)aio_pointer;
130  int res = 0;
131  int64_t seek_target = microseconds;
132  int64_t current_timestamp = 0;
133 
134  current_timestamp = aio->timestamp;
135  seek_target = av_rescale_q(seek_target, AV_TIME_BASE_Q, aio->stream->time_base);
136 #ifdef DEBUG
137  fprintf(stderr, "Current Timestamp = %" PRId64 ", seek_target = %" PRId64 "\n", current_timestamp, seek_target);
138 #endif
139  res = av_seek_frame(aio->format_context, aio->stream_index, seek_target, current_timestamp > seek_target ? AVSEEK_FLAG_BACKWARD : 0);
140  if (res < 0) {
141  throwIOExceptionIfError(env, res, "Failed to seek.");
142  goto bail;
143  }
144 
145  // make sure everything is flushed.
146  av_init_packet(&(aio->decode_packet));
147  aio->decode_packet.data = NULL;
148  aio->decode_packet.size = 0;
149  // flush codec
150  avcodec_flush_buffers(aio->decode_context);
151  // set timestamp to seek_target, since that's hopefully now our current timestamp..
152  aio->timestamp = seek_target;
153 
154  bail:
155 
156  return;
157 }
158 
166 JNIEXPORT void JNICALL Java_com_tagtraum_ffsampledsp_FFURLInputStream_close(JNIEnv *env, jobject stream, jlong aio_pointer) {
167  ff_audioio_free((FFAudioIO*)(intptr_t)aio_pointer);
168 }
int stream_index
Index of the audio stream we are using.
Definition: FFUtils.h:65
void throwIOExceptionIfError(JNIEnv *env, int err, const char *message)
Throws an IOException.
Definition: FFUtils.c:192
AVFormatContext * format_context
Current AVFormatContext.
Definition: FFUtils.h:63
AVStream * stream
Audio stream we are interested in.
Definition: FFUtils.h:64
JNIEXPORT void JNICALL Java_com_tagtraum_ffsampledsp_FFURLInputStream_seek(JNIEnv *env, jobject stream, jlong aio_pointer, jlong microseconds)
Seeks to a point in time.
JNIEXPORT void JNICALL Java_com_tagtraum_ffsampledsp_FFURLInputStream_close(JNIEnv *env, jobject stream, jlong aio_pointer)
Free all resources associated with a given FFAudioIO.
int ff_open_file(JNIEnv *env, AVFormatContext **format_context, AVStream **openedStream, AVCodecContext **context, int *stream_index, const char *url)
Opens the input file/url, allocates a AVFormatContext for it and opens the audio stream with an appro...
Definition: FFUtils.c:312
int ff_fill_buffer(FFAudioIO *aio)
Reads a frame via av_read_frame(AVFormatContext, AVPacket), decodes it to a AVPacket, and writes the result to the Java-side nativeBuffer.
Definition: FFUtils.c:897
int ff_init_audioio(JNIEnv *env, FFAudioIO *aio)
Initialize our main context FFAudioIO, so that SwrContext, decode buffers and the encoder are set to ...
Definition: FFUtils.c:549
AVPacket decode_packet
AVPacket for decoding.
Definition: FFUtils.h:67
JNIEXPORT jlong JNICALL Java_com_tagtraum_ffsampledsp_FFURLInputStream_open(JNIEnv *env, jobject stream, jstring url, jint streamIndex)
Open a file/URL and create a corresponding FFAudioIO.
JNIEnv * env
JNI environment.
Definition: FFUtils.h:58
JNIEXPORT void JNICALL Java_com_tagtraum_ffsampledsp_FFURLInputStream_fillNativeBuffer(JNIEnv *env, jobject stream, jlong aio_pointer)
Fills the java-side buffer (allocated via Java code) with fresh audio data.
JNIEXPORT jboolean JNICALL Java_com_tagtraum_ffsampledsp_FFURLInputStream_isSeekable(JNIEnv *env, jobject stream, jlong aio_pointer)
Indicates whether an FFAudioIO context is seekable.
AVCodecContext * decode_context
Codec context for decoding.
Definition: FFUtils.h:66
Central context representing the native peer to the Java FFNativePeerInputStream object.
Definition: FFUtils.h:56
void ff_audioio_free(FFAudioIO *aio)
Free all resources held by aio and then itself.
Definition: FFUtils.c:933
uint64_t timestamp
Current timestamp (in samples, not seconds)
Definition: FFUtils.h:72
jobject java_instance
Calling Java instance.
Definition: FFUtils.h:59