Форум программистов, компьютерный форум CyberForum.ru

Программирование Android

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 14, средняя оценка - 5.00
artemxl
0 / 0 / 0
Регистрация: 15.01.2013
Сообщений: 3
#1

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

15.01.2013, 05:29. Просмотров 1793. Ответов 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)


Помогите плиз решить проблемку.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
15.01.2013, 05:29
Здравствуйте! Я подобрал для вас темы с ответами на вопрос ffmpeg Выдернуть кадр из видеофайла (Программирование Android):

Склеить два видеофайла из SD карты в один - Программирование Android
Нужно склеить два видеофайла из sd карты в один. Оба одинаковых форматов, сняты на камеру. Слышал про FFMpeg но толком примеров не нашел....

Получить отдельный кадр с камеры - Программирование Android
У меня идет захват видео через камеру. Но мне нужно анализировать из этого видео кадры. Как правильно сохранять каждый кадр видео с...

Как в Android studio подключить ffmpeg - Программирование Android
Как подключить библиотеку ffmpeg в Android studio?? Я видел только в эклипс а в студию как подключить??

Как получить первый кадр из видеофайла - Visual Basic .NET
Здравствуйте, уважаемые форумчане. Прошу помощи в решении такой задачи: Как получить первый кадр из видеофайла. Практически, вопрос решен...

Ffmpeg. ошибка с разделением видеофайла - Видеопрограммы
Всем привет! Есть видеофайл длиной одна минута. Задача — вырезать из него последние десять секунд и сделать их отдельным файлом. ...

C++ builder + ffmpeg: вывести кадр на TImage - C++ Builder
я получаю кадр от ffmpeg в формате AVFrame. как вывести кадр на TImage ?

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
hellmin
36 / 36 / 2
Регистрация: 13.07.2011
Сообщений: 95
05.02.2013, 17:25 #2
Привет! Жуть как надо скомпилировать ffmpeg под Андроид)
Можешь дать ссылки на информацию, которой пользовался, а то все, что я находил мне не помогло(вероятно проблема в руках).
За одно у меня и проблема похожая... вместе разберемся.
И еще вопрос сколько весит приложение с ffmpeg?

По ссылке в топике, нашел все что надо)
V0v1k
1158 / 982 / 1
Регистрация: 28.06.2012
Сообщений: 3,462
05.02.2013, 17:53 #3
похоже на проблему синхронизации потоков.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.02.2013, 17:53
Привет! Вот еще темы с ответами:

Открытие видеофайла - Видеокамеры
Весь трабл в том, собственно, что с видео работать близко вообще не приходилось. Видео было снято на фотоаппарат. формат стоит .avi, но...

Просмотр видеофайла *kvd - Видеопрограммы
Видеокамера пишет каждый час 3 файла *.kvi, *.kvf, и *.kvd. Судя по размерам файлов собственно видео в файле *.kvd, если открыть файлик...

Граббинг аудиопотока из видеофайла - C#
Всем привет, есть такая задача. Необходимо написать программу, которая бы с видео вытягивала аудио дорожку и записывала ее в отдельный...

Как получить свойства видеофайла? - Visual Basic
Как получить свойства видеофайла кодек видео размер картинки кодек звука битрейт звука и т.д.


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Ответ Создать тему
Опции темы

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