title: Java.lang.UnsatisfiedLinkError: No implementation found for int
body: <p>I executed youtube watch me android application project. I just add some classes in my project and build with ndk. I got the error like  </p>
  
  <blockquote>
    <p>java.lang.UnsatisfiedLinkError: No implementation found for int com.ephronsystem.mobilizerapp.Ffmpeg.encodeVideoFrame(byte[]) (tried Java_com_ephronsystem_mobilizerapp_Ffmpeg_encodeVideoFrame and Java_com_ephronsystem_mobilizerapp_Ffmpeg_encodeVideoFrame___3B). </p>
  </blockquote>
  
  <p>My code:</p>
  
  <pre><code>package com.ephronsystem.mobilizerapp;
  
  public class Ffmpeg {
  
       static {
          System.loadLibrary("ffmpeg");
      }
  
      public static native boolean init(int width, int height, int audio_sample_rate, String rtmpUrl);
  
      public static native void shutdown();
  
      // Returns the size of the encoded frame.
      public static native int encodeVideoFrame(byte[] yuv_image);
  
      public static native int encodeAudioFrame(short[] audio_data, int length);
  }
  </code></pre>
  
  <p>This is ffmpeg-jni.c</p>
  
  <pre><code> #include &lt;android/log.h&gt;
  #include &lt;string.h&gt;
  #include &lt;jni.h&gt;
  #include "libavcodec/avcodec.h"
  #include "libavformat/avformat.h"
  #include "libavutil/opt.h"
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  JNIEXPORT jboolean JNICALL Java_com_ephronsystem_mobilizerapp_Ffmpeg_init(JNIEnv *env, jobject thiz,
                                                                   jint width, jint height,
                                                                   jint audio_sample_rate,
                                                                   jstring rtmp_url);
  JNIEXPORT void JNICALL Java_com_ephronsystem_mobilizerapp_Ffmpeg_shutdown(JNIEnv *env,
  jobject thiz
  );
  JNIEXPORT jint JNICALL Java_com_ephronsystem_mobilizerapp_Ffmpeg_encodeVideoFrame(JNIEnv
  *env,
  jobject thiz,
          jbyteArray
  yuv_image);
  JNIEXPORT jint JNICALL Java_com_ephronsystem_mobilizerapp_Ffmpeg_encodeAudioFrame(JNIEnv *env,
                                                                               jobject thiz,
                                                                               jshortArray audio_data,
                                                                               jint length);
  
  #ifdef __cplusplus
  }
  #endif
  
  #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "ffmpeg-jni", __VA_ARGS__)
  #define URL_WRONLY 2
          static AVFormatContext *fmt_context;
          static AVStream *video_stream;
          static AVStream *audio_stream;
  
          static int pts
  = 0;
  static int last_audio_pts = 0;
  
  // Buffers for UV format conversion
  static unsigned char *u_buf;
  static unsigned char *v_buf;
  
  static int enable_audio = 1;
  static int64_t audio_samples_written = 0;
  static int audio_sample_rate = 0;
  
  // Stupid buffer for audio samples. Not even a proper ring buffer
  #define AUDIO_MAX_BUF_SIZE 16384  // 2x what we get from Java
  static short audio_buf[AUDIO_MAX_BUF_SIZE];
  static int audio_buf_size = 0;
  
  void AudioBuffer_Push(const short *audio, int num_samples) {
      if (audio_buf_size &gt;= AUDIO_MAX_BUF_SIZE - num_samples) {
          LOGI("AUDIO BUFFER OVERFLOW: %i + %i &gt; %i", audio_buf_size, num_samples,
               AUDIO_MAX_BUF_SIZE);
          return;
      }
      for (int i = 0; i &lt; num_samples; i++) {
          audio_buf[audio_buf_size++] = audio[i];
      }
  }
  
  int AudioBuffer_Size() { return audio_buf_size; }
  
  short *AudioBuffer_Get() { return audio_buf; }
  
  void AudioBuffer_Pop(int num_samples) {
      if (num_samples &gt; audio_buf_size) {
          LOGI("Audio buffer Pop WTF: %i vs %i", num_samples, audio_buf_size);
          return;
      }
      memmove(audio_buf, audio_buf + num_samples, num_samples * sizeof(short));
      audio_buf_size -= num_samples;
  }
  
  void AudioBuffer_Clear() {
      memset(audio_buf, 0, sizeof(audio_buf));
      audio_buf_size = 0;
  }
  
  static void log_callback(void *ptr, int level, const char *fmt, va_list vl) {
      char x[2048];
      vsnprintf(x, 2048, fmt, vl);
      LOGI(x);
  }
  
  JNIEXPORT jboolean JNICALL Java_com_ephronsystem_mobilizerapp_Ffmpeg_init(JNIEnv *env, jobject thiz,
                                                                   jint width, jint height,
                                                                   jint audio_sample_rate_param,
                                                                   jstring rtmp_url) {
      avcodec_register_all();
      av_register_all();
      av_log_set_callback(log_callback);
  
      fmt_context = avformat_alloc_context();
      AVOutputFormat *ofmt = av_guess_format("flv", NULL, NULL);
      if (ofmt) {
          LOGI("av_guess_format returned %s", ofmt-&gt;long_name);
      } else {
          LOGI("av_guess_format fail");
          return JNI_FALSE;
      }
  
      fmt_context-&gt;oformat = ofmt;
      LOGI("creating video stream");
      video_stream = av_new_stream(fmt_context, 0);
  
      if (enable_audio) {
          LOGI("creating audio stream");
          audio_stream = av_new_stream(fmt_context, 1);
      }
  
      // Open Video Codec.
      // ======================
      AVCodec *video_codec = avcodec_find_encoder(AV_CODEC_ID_H264);
      if (!video_codec) {
          LOGI("Did not find the video codec");
          return JNI_FALSE;  // leak!
      } else {
          LOGI("Video codec found!");
      }
      AVCodecContext *video_codec_ctx = video_stream-&gt;codec;
      video_codec_ctx-&gt;codec_id = video_codec-&gt;id;
      video_codec_ctx-&gt;codec_type = AVMEDIA_TYPE_VIDEO;
      video_codec_ctx-&gt;level = 31;
  
      video_codec_ctx-&gt;width = width;
      video_codec_ctx-&gt;height = height;
      video_codec_ctx-&gt;pix_fmt = PIX_FMT_YUV420P;
      video_codec_ctx-&gt;rc_max_rate = 0;
      video_codec_ctx-&gt;rc_buffer_size = 0;
      video_codec_ctx-&gt;gop_size = 12;
      video_codec_ctx-&gt;max_b_frames = 0;
      video_codec_ctx-&gt;slices = 8;
      video_codec_ctx-&gt;b_frame_strategy = 1;
      video_codec_ctx-&gt;coder_type = 0;
      video_codec_ctx-&gt;me_cmp = 1;
      video_codec_ctx-&gt;me_range = 16;
      video_codec_ctx-&gt;qmin = 10;
      video_codec_ctx-&gt;qmax = 51;
      video_codec_ctx-&gt;keyint_min = 25;
      video_codec_ctx-&gt;refs = 3;
      video_codec_ctx-&gt;trellis = 0;
      video_codec_ctx-&gt;scenechange_threshold = 40;
      video_codec_ctx-&gt;flags |= CODEC_FLAG_LOOP_FILTER;
      video_codec_ctx-&gt;me_method = ME_HEX;
      video_codec_ctx-&gt;me_subpel_quality = 6;
      video_codec_ctx-&gt;i_quant_factor = 0.71;
      video_codec_ctx-&gt;qcompress = 0.6;
      video_codec_ctx-&gt;max_qdiff = 4;
      video_codec_ctx-&gt;time_base.den = 10;
      video_codec_ctx-&gt;time_base.num = 1;
      video_codec_ctx-&gt;bit_rate = 3200 * 1000;
      video_codec_ctx-&gt;bit_rate_tolerance = 0;
      video_codec_ctx-&gt;flags2 |= 0x00000100;
  
      fmt_context-&gt;bit_rate = 4000 * 1000;
  
      av_opt_set(video_codec_ctx, "partitions", "i8x8,i4x4,p8x8,b8x8", 0);
      av_opt_set_int(video_codec_ctx, "direct-pred", 1, 0);
      av_opt_set_int(video_codec_ctx, "rc-lookahead", 0, 0);
      av_opt_set_int(video_codec_ctx, "fast-pskip", 1, 0);
      av_opt_set_int(video_codec_ctx, "mixed-refs", 1, 0);
      av_opt_set_int(video_codec_ctx, "8x8dct", 0, 0);
      av_opt_set_int(video_codec_ctx, "weightb", 0, 0);
  
      if (fmt_context-&gt;oformat-&gt;flags &amp; AVFMT_GLOBALHEADER)
          video_codec_ctx-&gt;flags |= CODEC_FLAG_GLOBAL_HEADER;
  
      LOGI("Opening video codec");
      AVDictionary *vopts = NULL;
      av_dict_set(&amp;vopts, "profile", "main", 0);
      //av_dict_set(&amp;vopts, "vprofile", "main", 0);
      av_dict_set(&amp;vopts, "rc-lookahead", 0, 0);
      av_dict_set(&amp;vopts, "tune", "film", 0);
      av_dict_set(&amp;vopts, "preset", "ultrafast", 0);
      av_opt_set(video_codec_ctx-&gt;priv_data, "tune", "film", 0);
      av_opt_set(video_codec_ctx-&gt;priv_data, "preset", "ultrafast", 0);
      av_opt_set(video_codec_ctx-&gt;priv_data, "tune", "film", 0);
      int open_res = avcodec_open2(video_codec_ctx, video_codec, &amp;vopts);
      if (open_res &lt; 0) {
          LOGI("Error opening video codec: %i", open_res);
          return JNI_FALSE;   // leak!
      }
  
      // Open Audio Codec.
      // ======================
  
      if (enable_audio) {
          AudioBuffer_Clear();
          audio_sample_rate = audio_sample_rate_param;
          AVCodec *audio_codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
          if (!audio_codec) {
              LOGI("Did not find the audio codec");
              return JNI_FALSE;  // leak!
          } else {
              LOGI("Audio codec found!");
          }
          AVCodecContext *audio_codec_ctx = audio_stream-&gt;codec;
          audio_codec_ctx-&gt;codec_id = audio_codec-&gt;id;
          audio_codec_ctx-&gt;codec_type = AVMEDIA_TYPE_AUDIO;
          audio_codec_ctx-&gt;bit_rate = 128000;
          audio_codec_ctx-&gt;bit_rate_tolerance = 16000;
          audio_codec_ctx-&gt;channels = 1;
          audio_codec_ctx-&gt;profile = FF_PROFILE_AAC_LOW;
          audio_codec_ctx-&gt;sample_fmt = AV_SAMPLE_FMT_FLT;
          audio_codec_ctx-&gt;sample_rate = 44100;
  
          LOGI("Opening audio codec");
          AVDictionary *opts = NULL;
          av_dict_set(&amp;opts, "strict", "experimental", 0);
          open_res = avcodec_open2(audio_codec_ctx, audio_codec, &amp;opts);
          LOGI("audio frame size: %i", audio_codec_ctx-&gt;frame_size);
  
          if (open_res &lt; 0) {
              LOGI("Error opening audio codec: %i", open_res);
              return JNI_FALSE;   // leak!
          }
      }
  
      const jbyte *url = (*env)-&gt;GetStringUTFChars(env, rtmp_url, NULL);
  
      // Point to an output file
      if (!(ofmt-&gt;flags &amp; AVFMT_NOFILE)) {
          if (avio_open(&amp;fmt_context-&gt;pb, url, URL_WRONLY) &lt; 0) {
              LOGI("ERROR: Could not open file %s", url);
              return JNI_FALSE;  // leak!
          }
      }
      (*env)-&gt;ReleaseStringUTFChars(env, rtmp_url, url);
  
      LOGI("Writing output header.");
      // Write file header
      if (avformat_write_header(fmt_context, NULL) != 0) {
          LOGI("ERROR: av_write_header failed");
          return JNI_FALSE;
      }
  
      pts = 0;
      last_audio_pts = 0;
      audio_samples_written = 0;
  
      // Initialize buffers for UV format conversion
      int frame_size = video_codec_ctx-&gt;width * video_codec_ctx-&gt;height;
      u_buf = (unsigned char *) av_malloc(frame_size / 4);
      v_buf = (unsigned char *) av_malloc(frame_size / 4);
  
      LOGI("ffmpeg encoding init done");
      return JNI_TRUE;
  }
  
  JNIEXPORT void JNICALL Java_com_ephronsystem_mobilizerapp_Ffmpeg_shutdown(JNIEnv
  *env,
  jobject thiz
  ) {
  av_write_trailer(fmt_context);
  avio_close(fmt_context
  -&gt;pb);
  avcodec_close(video_stream
  -&gt;codec);
  if (enable_audio) {
  avcodec_close(audio_stream
  -&gt;codec);
  }
  av_free(fmt_context);
  av_free(u_buf);
  av_free(v_buf);
  
  fmt_context = NULL;
  u_buf = NULL;
  v_buf = NULL;
  }
  
  JNIEXPORT jint JNICALL Java_com_ephronsystem_mobilizerapp_Ffmpeg_encodeVideoFrame(JNIEnv
  *env,
  jobject thiz,
          jbyteArray
  yuv_image) {
  int yuv_length = (*env)-&gt;GetArrayLength(env, yuv_image);
  unsigned char *yuv_data = (*env)-&gt;GetByteArrayElements(env, yuv_image, 0);
  
  AVCodecContext *video_codec_ctx = video_stream-&gt;codec;
  //LOGI("Yuv size: %i w: %i h: %i", yuv_length, video_codec_ctx-&gt;width, video_codec_ctx-&gt;height);
  
  int frame_size = video_codec_ctx-&gt;width * video_codec_ctx-&gt;height;
  
  const unsigned char *uv = yuv_data + frame_size;
  
  // Convert YUV from NV12 to I420. Y channel is the same so we don't touch it,
  // we just have to deinterleave UV.
  for (
  int i = 0;
  i &lt; frame_size / 4; i++) {
  v_buf[i] = uv[i * 2];
  u_buf[i] = uv[i * 2 + 1];
  }
  
  AVFrame source;
  memset(&amp;source, 0, sizeof(AVFrame));
  source.data[0] =
  yuv_data;
  source.data[1] =
  u_buf;
  source.data[2] =
  v_buf;
  source.linesize[0] = video_codec_ctx-&gt;
  width;
  source.linesize[1] = video_codec_ctx-&gt;width / 2;
  source.linesize[2] = video_codec_ctx-&gt;width / 2;
  
  // only for bitrate regulation. irrelevant for sync.
  source.
  pts = pts;
  pts++;
  
  int out_length = frame_size + (frame_size / 2);
  unsigned char *out = (unsigned char *) av_malloc(out_length);
  int compressed_length = avcodec_encode_video(video_codec_ctx, out, out_length, &amp;source);
  
  (*env)-&gt;
  ReleaseByteArrayElements(env, yuv_image, yuv_data,
  0);
  
  // Write to file too
  if (compressed_length &gt; 0) {
  AVPacket pkt;
  av_init_packet(&amp;pkt);
  pkt.
  pts = last_audio_pts;
  if (video_codec_ctx-&gt;coded_frame &amp;&amp; video_codec_ctx-&gt;coded_frame-&gt;key_frame) {
  pkt.flags |= 0x0001;
  }
  pkt.
  stream_index = video_stream-&gt;index;
  pkt.
  data = out;
  pkt.
  size = compressed_length;
  if (
  av_interleaved_write_frame(fmt_context,
  &amp;pkt) != 0) {
  LOGI("Error writing video frame");
  }
  } else {
  LOGI("??? compressed_length &lt;= 0");
  }
  
  last_audio_pts++;
  
  av_free(out);
  return
  compressed_length;
  }
  
  JNIEXPORT jint JNICALL Java_com_ephronsystem_mobilizerapp_Ffmpeg_encodeAudioFrame(JNIEnv
  *env,
  jobject thiz,
          jshortArray
  audio_data,
  jint length
  ) {
  if (!enable_audio) {
  return 0;
  }
  
  short *audio = (*env)-&gt;GetShortArrayElements(env, audio_data, 0);
  //LOGI("java audio buffer size: %i", length);
  
  AVCodecContext *audio_codec_ctx = audio_stream-&gt;codec;
  
  unsigned char *out = av_malloc(128000);
  
  AudioBuffer_Push(audio, length
  );
  
  int total_compressed = 0;
  while (
  
  AudioBuffer_Size()
  
  &gt;= audio_codec_ctx-&gt;frame_size) {
  AVPacket pkt;
  av_init_packet(&amp;pkt);
  
  int compressed_length = avcodec_encode_audio(audio_codec_ctx, out, 128000,
                                               AudioBuffer_Get());
  
  total_compressed +=
  compressed_length;
  audio_samples_written += audio_codec_ctx-&gt;
  frame_size;
  
  int new_pts = (audio_samples_written * 1000) / audio_sample_rate;
  if (compressed_length &gt; 0) {
  pkt.
  size = compressed_length;
  pkt.
  pts = new_pts;
  last_audio_pts = new_pts;
  //LOGI("audio_samples_written: %i  comp_length: %i   pts: %i", (int)audio_samples_written, (int)compressed_length, (int)new_pts);
  pkt.flags |= 0x0001;
  pkt.
  stream_index = audio_stream-&gt;index;
  pkt.
  data = out;
  if (
  av_interleaved_write_frame(fmt_context,
  &amp;pkt) != 0) {
  LOGI("Error writing audio frame");
  }
  }
  AudioBuffer_Pop(audio_codec_ctx
  -&gt;frame_size);
  }
  
  (*env)-&gt;
  ReleaseShortArrayElements(env, audio_data, audio,
  0);
  
  av_free(out);
  return
  total_compressed;
  }
  </code></pre>