Форум программистов, компьютерный форум, киберфорум
Наши страницы

ffmpeg Выдернуть кадр из видеофайла - Программирование Android

Войти
Регистрация
Восстановить пароль
Другие темы раздела
Программирование Android выделение и освобождение памяти для нативных функций http://www.cyberforum.ru/android-dev/thread762047.html
Доброго времени суток. Пытаюсь разобраться с использованием android-ndk. Столкнулся с такой проблемкой: Нужно выделить буфер для использования на стороне jni, а затем освободить его. Нашел вот...
Программирование Android Работа с камерой Попытался поработать с камерой, но при попытке фотографирования приложение вылетает, при этом камера в эмуляторе работает, но почему то не использует вебку, хотя я и указал в Back camera вариант... http://www.cyberforum.ru/android-dev/thread761799.html
Программирование Android Добавление записи в БД (использование put)
Необходимо в БД добавить запись с данными введенными в активити. Сама БД создана. Далее функция добавления После комментирования кусков кода выявлено что ошибка возникает из-за использования ...
Установка по для разработки под Android Программирование Android
Испытываю трудности по установке по на windows x64.. Ставлю JDK x64 после пытался из exe SDK android но не находит JDK... Поставил из zip архива вместе с eclipse и скачал в eclipse версии нужные...
Программирование Android Сборка приложения NDK sample в Eclipse http://www.cyberforum.ru/android-dev/thread761452.html
Здравствуйте. Пытаюсь освоить программирование с использованием NDK. Хочу для начала собрать приложение из готового примера. В Eclipse открываю Android project from existing code. Указываю пример...
Программирование Android Настройка Eclipse для работы с NDK Итак, установил я NDK, SDK. В пакете с SDK есть и Eclipse со всеми плагинами. В настройках прописал пути до NDK и SDK. Создаю обычный Android Application Project. Правой кнопкой мыши на нём... подробнее

Показать сообщение отдельно
artemxl
0 / 0 / 0
Регистрация: 15.01.2013
Сообщений: 3

ffmpeg Выдернуть кадр из видеофайла - Программирование Android

15.01.2013, 05:29. Просмотров 1868. Ответов 2
Метки (Все метки)

Доброго времени суток.
Бьюсь 4й день над проблемкой как при помощи ffmpeg выдернуть определенный кадр из видеофайла и передать его на сторону Java.
Вот что я сделал: Скомпилировал библиотеку ffmpeg, проверил на примерах все работает. Но вот пример как дернуть кадр из видео нашел лишь 1 вот тут.
Попробовал его у себя, получилось примерно следующее:
Код Библиотеки:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
#include <jni.h>
#include <android/log.h>
 
#include "libavutil/pixfmt.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "cmdutils.h"
 
#define LOG_TAG "com.domain.tag"
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
const int ERROR_OPEN_FILE = -1;
const int ERROR_FIND_VIDEOSTREAM = -2;
const int ERROR_FIND_VIDEODECODER = -3;
const int ERROR_OPEN_VIDEODECODER = -4;
const int ERROR_NO_STREAM_INFO = -5;
 
typedef long thandle_file;
// Handle для файла - полная информация об открытом файле
struct thandle {
 AVFormatContext* ctx;
 AVCodecContext* codecCtx;
 int videoStream;
 AVPacket* packet;
} tHandle;
 
//отправляем в JAVA исключение с кодом errorCode
void make_exception(JNIEnv *env, int errorCode) {
 LOGI("exception %d", errorCode);
 char buffer[32];
 sprintf(buffer, "%d", errorCode);
 (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/Exception"), buffer);
}
 
//инициализация
jint Java_ru_dzakhov_ffmpeg_test_FFMpegWrapper_initialize(JNIEnv *env) {
 av_register_all();
 LOGI("initialize_passed");
 return 0;
}
 
//определить размер кадра в формате Bitmap.Config.ARGB_8888
jint Java_ru_dzakhov_ffmpeg_test_FFMpegWrapper_getFrameBufferSize(JNIEnv *env, jobject thiz, thandle_file handleFile, jint width, jint height)
{
    return 0;
    }
//открыть файл, получить handle
jint Java_ru_dzakhov_ffmpeg_test_FFMpegWrapper_openFile(JNIEnv *env, jobject thiz, jstring fileName) {
AVFormatContext* ctx = 0;
const char *filename = (*env)->GetStringUTFChars(env, fileName, 0);
 
if(av_open_input_file(&ctx, filename, NULL, 0, NULL) != 0) {
  make_exception(env, ERROR_OPEN_FILE); //"Не удалось открыть видеофайл
  LOGI("not open");
}
 
// Retrieve stream information
if(av_find_stream_info(ctx)< 0) {
  make_exception(env, ERROR_NO_STREAM_INFO); //"Не удалось открыть видеофайл; // Couldn't find stream information
  LOGI("not open");
}
 
int videoStream = -1;
int i = 0;
for (i = 0; i < ctx->nb_streams; ++i) {
 if (ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
  videoStream = i;
  break;
 }
}
if (videoStream == -1) make_exception(env, ERROR_FIND_VIDEOSTREAM);
 
AVCodecContext* codecCtx = ctx->streams[videoStream]->codec;
AVCodec* codec = avcodec_find_decoder(codecCtx->codec_id);
 
if (codec == 0) {
 make_exception(env, ERROR_FIND_VIDEODECODER);
}
 
if (avcodec_open2(codecCtx, codec, 0) != 0) {
 make_exception(env, ERROR_OPEN_VIDEODECODER);
}
AVPacket* packet = (AVPacket*)malloc(sizeof(struct AVPacket));
av_init_packet(packet);
 
struct thandle* h = malloc(sizeof(struct thandle));
h->ctx = ctx;
h->codecCtx = codecCtx;
h->videoStream = videoStream;
h->packet = packet;
LOGI("openened");
//release java string
(*env)->ReleaseStringUTFChars(env, fileName, filename);
return (unsigned long)h;
}
 
//выдрать из открытого файла фрейм в формате Bitmap.Config.ARGB_8888
//в заданных размерах
//и сохранить битмапку в переданный Java объект java.nio.ByteBuffer
//время timeUS задается в микросекундах.
jint Java_ru_dzakhov_ffmpeg_test_FFMpegWrapper_getFrame(JNIEnv *env, jobject thiz, jstring fileName, jlong timeUS, jint width, jint height, jobject buffer) {
////////////////////////////////////////////////
    AVFormatContext* ctx = 0;
    const char *filename = (*env)->GetStringUTFChars(env, fileName, 0);
 
    if(av_open_input_file(&ctx, filename, NULL, 0, NULL) != 0) {
      make_exception(env, ERROR_OPEN_FILE); //"Не удалось открыть видеофайл
      LOGI("not open");
    }
 
    // Retrieve stream information
    if(av_find_stream_info(ctx)< 0) {
      make_exception(env, ERROR_NO_STREAM_INFO); //"Не удалось открыть видеофайл; // Couldn't find stream information
      LOGI("not open");
    }
 
    int videoStream = -1;
    int i = 0;
    for (i = 0; i < ctx->nb_streams; ++i) {
     if (ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
      videoStream = i;
      break;
     }
    }
    if (videoStream == -1) make_exception(env, ERROR_FIND_VIDEOSTREAM);
 
    AVCodecContext* codecCtx = ctx->streams[videoStream]->codec;
    AVCodec* codec = avcodec_find_decoder(codecCtx->codec_id);
 
    if (codec == 0) {
     make_exception(env, ERROR_FIND_VIDEODECODER);
    }
 
    if (avcodec_open2(codecCtx, codec, 0) != 0) {
     make_exception(env, ERROR_OPEN_VIDEODECODER);
    }
    AVPacket* packet = (AVPacket*)malloc(sizeof(struct AVPacket));
    av_init_packet(packet);
 
    struct thandle* h = malloc(sizeof(struct thandle));
    h->ctx = ctx;
    h->codecCtx = codecCtx;
    h->videoStream = videoStream;
    h->packet = packet;
    LOGI("openened");
    //release java string
    (*env)->ReleaseStringUTFChars(env, fileName, filename);
    //struct thandle* hf = (unsigned long)h;
    ///////////////////////////////////////////
//Функция для выдирания заданного фрейма из открытого файла
    LOGI("file= %d",h);
ctx = ((struct thandle*)h)->ctx;
codecCtx = ((struct thandle*)h)->codecCtx;
packet =  ((struct thandle*)h)->packet;
videoStream = ((struct thandle*)h)->videoStream;
long shortBuffer = buffer;
jshort* buff = (jshort*) (*env)->GetDirectBufferAddress(env, shortBuffer);
 
AVFrame* frame = avcodec_alloc_frame(); //YUV frame
avcodec_get_frame_defaults(frame);
 
//AV_TIME_BASE * time_in_seconds = avcodec_timestamp
//см. [url]http://dranger.com/ffmpeg/tutorial07.html[/url]
int frameNumber = timeUS;
int64_t pos = frameNumber * AV_TIME_BASE / 1000000;
int64_t seek_target= av_rescale_q(pos, AV_TIME_BASE_Q, ctx->streams[videoStream]->time_base);
//LOGI("seek_target= ");
//выполняем seek - попадаем на ближайший кейфрейм
//затем ищем нужный кадр.
int res = avformat_seek_file(ctx
 , videoStream
 , INT64_MIN
 , seek_target//* AV_TIME_BASE
 , INT64_MAX
 , 0);
LOGI("seek: %d f=%ld pos=%lld st=%lld", res, frameNumber, (int64_t)pos, seek_target);
if (res >= 0) {
 avcodec_flush_buffers(codecCtx);
 LOGI("flushed");
}
av_init_packet(packet);
 
AVFrame* frameRGB = avcodec_alloc_frame();
avcodec_get_frame_defaults(frameRGB);
 
enum PixelFormat pixel_format = PIX_FMT_RGBA;
avpicture_fill((AVPicture*) frameRGB
 , (uint8_t*)buff
 , pixel_format
 , width
 , height
);
 
while (av_read_frame(ctx, packet) == 0) {
 LOGI("pts=%lld st=%lld", packet->pts, seek_target);
 if (packet->stream_index == videoStream) {
  int gotPicture = 0;
  int bytesDecompressed = avcodec_decode_video2(codecCtx, frame, &gotPicture, packet);
    if (gotPicture && packet->pts >= seek_target) {
        LOGI("opana");
    // конвертируем данные из формата YUV в RGB24
    struct SwsContext* scaleCtx = sws_getContext(frame->width,
      frame->height,
      (enum PixelFormat)frame->format
      , width //frame->width,
      , height //frame->height,
      , pixel_format
      , SWS_BICUBIC
      , 0, 0, 0);
 
    int height = sws_scale(scaleCtx
      , frame->data
      , frame->linesize
      , 0
      , frame->height
      , frameRGB->data
      , frameRGB->linesize);
   break;
   }
  av_free_packet(packet);
  }
}
LOGI("ended");
av_free(frameRGB);
av_free(frame);
return 0;
}
 
 
jint Java_ru_dzakhov_ffmpeg_test_FFMpegWrapper_logFileInfo(JNIEnv * env, jobject this, jstring filename)
{
    av_register_all();
 
    AVFormatContext *pFormatCtx;
    const jbyte *str;
    str = (*env)->GetStringUTFChars(env, filename, NULL);
 
    if(av_open_input_file(&pFormatCtx, str, NULL, 0, NULL)!=0)
    {
        LOGE("Can't open file '%s'\n", str);
        return 1;
    }
    else
    {
        LOGI("File was opened\n");
        LOGI("File '%s', Codec %s",
            pFormatCtx->filename,
            pFormatCtx->iformat->name
        );
    }
    return 0;
}
 
jobject Java_ru_dzakhov_ffmpeg_test_FFMpegWrapper_allocNative(JNIEnv* env, jobject thiz, jlong size)
{
     void* buffer = malloc(size);
        jobject directBuffer = (*env)->NewDirectByteBuffer(env,buffer, size);
        return directBuffer;
}
void Java_ru_dzakhov_ffmpeg_test_FFMpegWrapper_freeNative(JNIEnv* env, jobject thiz, jobject globalRef)
{
    void *buffer = (*env)->GetDirectBufferAddress(env, globalRef);
        free(buffer);
}
Код Java:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package ru.dzakhov.ffmpeg.test;
 
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
 
public class FFMpegWrapper {
    static {
        System.loadLibrary("mylib");
        initialize();
    } 
private static native int initialize();
public static native long openFile(String fileName);
public static native int getFrameBufferSize(long handleFile, int format, int width, int height);
public static native int getFrame(String fileName, long timeUS, int width, int height, java.nio.Buffer buffer);
public static native int logFileInfo(String filename);
/** Выделить нативный буфер заданного размера*/
public static native ByteBuffer allocNative(long bufferSize);
 
/** Освободить нативный буфер заданного размера*/
public static native void freeNative(ByteBuffer my_buffer);
 
}
и наконец мэйнактивити:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package ru.dzakhov.ffmpeg.test;
 
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.nio.channels.ScatteringByteChannel;
 
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import ru.dzakhov.ffmpeg.test.FFMpegWrapper;
 
public class MainActivity extends Activity {
 
// private static native int logFileInfo(String filename);
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //FFMpegWrapper.openFile("/storage/sdcard0/Movies/cool.wmv");
        int width = 60;
        int height =39;
        long timeUS =1000;
        // = 1024;
        //ByteBuffer my_buffer = FFMpegWrapper.allocNative(bufferSize);//.asFloatBuffer();// asShortBuffer();
        long handle = FFMpegWrapper.openFile("/storage/sdcard0/Movies/126_3_17.avi");
        long bufferSize = 1024;//FFMpegWrapper.getFrameBufferSize(handle, Bitmap.Config.ARGB_8888.hashCode(), width, height);
        ByteBuffer my_buffer = FFMpegWrapper.allocNative(bufferSize);//.asShortBuffer();
        Log.i("ttag",toString().valueOf(handle));
        Log.i("ttag",toString().valueOf(my_buffer));
        //long ww = FFMpegWrapper.getFrameBufferSize(handle, RESULT_OK, 60, 39);
        //Log.i("ttag",toString().valueOf(ww));
        FFMpegWrapper.getFrame("/storage/sdcard0/Movies/126_3_17.avi", timeUS, width, height, my_buffer);
        //Bitmap dest = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        //Buffer buffer = null;
        //dest.copyPixelsFromBuffer(buffer);
        //Ура, мы получили в dest битмапку c извлеченным кадром :)
      FFMpegWrapper.logFileInfo("/storage/sdcard0/Movies/126_3_17.avi");
      FFMpegWrapper.freeNative(my_buffer);
    }
 
 
}
В общем суть в том что в функции getFrame что-то идет не так, подозреваю неправильно рассчитывается seek_target (он почемуто всегда равен нулю, какое бы время я не передавал в функцию)
и естественно программа вылетает в момент когда попадает вот сюда "if (gotPicture && packet->pts >= seek_target) {
"
Вот лог во время запуска программы:

01-15 13:07:30.490: D/dalvikvm(8440): Trying to load lib /data/data/ru.dzakhov.ffmpeg.test/lib/libmylib.so 0x41cb7df8
01-15 13:07:30.495: D/dalvikvm(8440): Added shared lib /data/data/ru.dzakhov.ffmpeg.test/lib/libmylib.so 0x41cb7df8
01-15 13:07:30.495: D/dalvikvm(8440): No JNI_OnLoad found in /data/data/ru.dzakhov.ffmpeg.test/lib/libmylib.so 0x41cb7df8, skipping init
01-15 13:07:30.495: I/com.domain.tag(8440): initialize_passed
01-15 13:07:30.540: I/com.domain.tag(8440): openened
01-15 13:07:30.540: I/ttag(8440): 3270391527096277528
01-15 13:07:30.540: I/ttag(8440): java.nio.ReadWriteDirectByteBuffer, status: capacity=1024 position=0 limit=1024
01-15 13:07:30.595: I/com.domain.tag(8440): openened
01-15 13:07:30.595: I/com.domain.tag(8440): file= 1089515320
01-15 13:07:30.595: I/com.domain.tag(8440): seek: 0 f=1000 pos=1000 st=0
01-15 13:07:30.595: I/com.domain.tag(8440): flushed
01-15 13:07:30.595: I/com.domain.tag(8440): pts=0 st=0
01-15 13:07:30.595: I/com.domain.tag(8440): pts=1024 st=0
01-15 13:07:30.595: I/com.domain.tag(8440): pts=2048 st=0
01-15 13:07:30.595: I/com.domain.tag(8440): pts=3072 st=0
01-15 13:07:30.595: I/com.domain.tag(8440): pts=4096 st=0
01-15 13:07:30.595: I/com.domain.tag(8440): pts=5120 st=0
01-15 13:07:30.595: I/com.domain.tag(8440): pts=6144 st=0
01-15 13:07:30.595: I/com.domain.tag(8440): pts=7168 st=0
01-15 13:07:30.595: I/com.domain.tag(8440): pts=8192 st=0
01-15 13:07:30.595: I/com.domain.tag(8440): pts=9216 st=0
01-15 13:07:30.600: I/com.domain.tag(8440): pts=10240 st=0
01-15 13:07:30.600: I/com.domain.tag(8440): pts=11264 st=0
01-15 13:07:30.600: I/com.domain.tag(8440): pts=12288 st=0
01-15 13:07:30.600: I/com.domain.tag(8440): pts=13312 st=0
01-15 13:07:30.600: I/com.domain.tag(8440): pts=14336 st=0
01-15 13:07:30.600: I/com.domain.tag(8440): pts=15360 st=0
01-15 13:07:30.600: I/com.domain.tag(8440): pts=16384 st=0
01-15 13:07:30.600: I/com.domain.tag(8440): pts=0 st=0
01-15 13:07:30.635: I/com.domain.tag(8440): opana
01-15 13:07:30.715: A/libc(8440): Fatal signal 11 (SIGSEGV) at 0x48258000 (code=2), thread 8440 (hov.ffmpeg.test)


Помогите плиз решить проблемку.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru