OSDN Git Service

Revert "stagefright-plugins: Protect against crash"
[android-x86/external-stagefright-plugins.git] / utils / ffmpeg_utils.cpp
index ba51ff1..e1d961b 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2012 Michael Chen <omxcodec@gmail.com>
+ * Copyright 2015 The CyanogenMod Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_NDEBUG 0
+
+//#define LOG_NDEBUG 0
 #define LOG_TAG "FFMPEG"
 #include <utils/Log.h>
 
 extern "C" {
 #endif
 
+#include "config.h"
+
 #include <unistd.h>
 #include <stdlib.h>
 #include <inttypes.h>
 #include <math.h>
-#include <signal.h>
 #include <limits.h> /* INT_MAX */
-
-#include "config.h"
-#include "libavutil/avstring.h"
-#include "libavutil/colorspace.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/dict.h"
-#include "libavutil/parseutils.h"
-#include "libavutil/samplefmt.h"
-#include "libavutil/avassert.h"
-#include "libavutil/intreadwrite.h"
-#include "libavformat/avformat.h"
-#include "libavdevice/avdevice.h"
-#include "libswscale/swscale.h"
-#include "libavcodec/audioconvert.h"
-#include "libavutil/opt.h"
-#include "libavutil/internal.h"
-#include "libavcodec/avfft.h"
-#include "libswresample/swresample.h"
-
-#include "cmdutils.h"
+#include <time.h>
 
 #undef strncpy
 #include <string.h>
@@ -59,6 +41,11 @@ extern "C" {
 }
 #endif
 
+#include <cutils/properties.h>
+
+#include "ffmpeg_utils.h"
+#include "ffmpeg_source.h"
+
 // log
 static int flags;
 
@@ -67,33 +54,12 @@ const char program_name[] = "dummy";
 const int program_birth_year = 2012;
 
 // init ffmpeg
-static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
-static int ref_count = 0;
+static pthread_mutex_t s_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+static int s_ref_count = 0;
 
 namespace android {
 
 //////////////////////////////////////////////////////////////////////////////////
-// dummy
-//////////////////////////////////////////////////////////////////////////////////
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void av_noreturn exit_program(int ret)
-{
-    // do nothing
-}
-
-void show_help_default(const char *opt, const char *arg)
-{
-    // do nothing
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-//////////////////////////////////////////////////////////////////////////////////
 // log
 //////////////////////////////////////////////////////////////////////////////////
 static void sanitize(uint8_t *line){
@@ -104,6 +70,7 @@ static void sanitize(uint8_t *line){
     }
 }
 
+// TODO, remove static variables to support multi-instances
 void nam_av_log_callback(void* ptr, int level, const char* fmt, va_list vl)
 {
     static int print_prefix = 1;
@@ -121,14 +88,14 @@ void nam_av_log_callback(void* ptr, int level, const char* fmt, va_list vl)
         return;
     }
     if (count > 0) {
-        LOGI("Last message repeated %d times\n", count);
+        ALOGI("Last message repeated %d times\n", count);
         count = 0;
     }
     strcpy(prev, line);
     sanitize((uint8_t *)line);
 
 #if 0
-    LOGI("%s", line);
+    ALOGI("%s", line);
 #else
 #define LOG_BUF_SIZE 1024
     static char g_msg[LOG_BUF_SIZE];
@@ -156,7 +123,7 @@ void nam_av_log_callback(void* ptr, int level, const char* fmt, va_list vl)
             g_msg_len += 1;
             g_msg[g_msg_len] = '\n';
         }
-        LOGI("%s", g_msg);
+        ALOGI("%s", g_msg);
         /* reset g_msg and g_msg_len */
         memset(g_msg, 0, LOG_BUF_SIZE);
         g_msg_len = 0;
@@ -215,63 +182,80 @@ static int lockmgr(void **mtx, enum AVLockOp op)
     return 1;
 }
 
+/**
+ * To debug ffmpeg", type this command on the console before starting playback:
+ *     setprop debug.nam.ffmpeg 1
+ * To disable the debug, type:
+ *     setprop debug.nam.ffmpge 0
+*/
 status_t initFFmpeg() 
 {
     status_t ret = OK;
+    bool debug_enabled = false;
+    char value[PROPERTY_VALUE_MAX];
+
+    pthread_mutex_lock(&s_init_mutex);
 
-    pthread_mutex_lock(&init_mutex);
+    if (property_get("debug.nam.ffmpeg", value, NULL)
+        && (!strcmp(value, "1") || !av_strcasecmp(value, "true"))) {
+        ALOGI("set ffmpeg debug level to AV_LOG_DEBUG");
+        debug_enabled = true;
+    }
+    if (debug_enabled)
+        av_log_set_level(AV_LOG_DEBUG);
+    else
+        av_log_set_level(AV_LOG_INFO);
 
-    if(ref_count == 0) {
+    if(s_ref_count == 0) {
         nam_av_log_set_flags(AV_LOG_SKIP_REPEATED);
-        //av_log_set_level(AV_LOG_DEBUG);
         av_log_set_callback(nam_av_log_callback);
 
         /* register all codecs, demux and protocols */
         avcodec_register_all();
-#if CONFIG_AVDEVICE
+#if 0
         avdevice_register_all();
 #endif
         av_register_all();
         avformat_network_init();
 
-        init_opts();
+        /* register android source */
+        ffmpeg_register_android_source();
 
         if (av_lockmgr_register(lockmgr)) {
-            LOGE("could not initialize lock manager!");
+            ALOGE("could not initialize lock manager!");
             ret = NO_INIT;
         }
     }
 
     // update counter
-    ref_count++;
+    s_ref_count++;
 
-    pthread_mutex_unlock(&init_mutex);
+    pthread_mutex_unlock(&s_init_mutex);
 
     return ret;
 }
 
 void deInitFFmpeg()
 {
-    pthread_mutex_lock(&init_mutex);
+    pthread_mutex_lock(&s_init_mutex);
 
     // update counter
-    ref_count--;
+    s_ref_count--;
 
-    if(ref_count == 0) {
+    if(s_ref_count == 0) {
         av_lockmgr_register(NULL);
-        uninit_opts();
         avformat_network_deinit();
     }
 
-    pthread_mutex_unlock(&init_mutex);
+    pthread_mutex_unlock(&s_init_mutex);
 }
 
 //////////////////////////////////////////////////////////////////////////////////
 // parser
 //////////////////////////////////////////////////////////////////////////////////
-/* H.264 bitstream with start codes, NOT AVC1! ref: libavcodec/h264_parser.c */
-static int h264_split(AVCodecContext *avctx,
-                      const uint8_t *buf, int buf_size, int check_compatible_only)
+/* H.264 bitstream with start codes, NOT AVC1! */
+static int h264_split(AVCodecContext *avctx __unused,
+        const uint8_t *buf, int buf_size, int check_compatible_only)
 {
     int i;
     uint32_t state = -1;
@@ -282,16 +266,19 @@ static int h264_split(AVCodecContext *avctx,
 
     for(i=0; i<=buf_size; i++){
         if((state&0xFFFFFF1F) == 0x107) {
-            LOGI("found NAL_SPS");
+            ALOGI("found NAL_SPS");
             has_sps=1;
         }
         if((state&0xFFFFFF1F) == 0x108) {
-            LOGI("found NAL_PPS");
+            ALOGI("found NAL_PPS");
             has_pps=1;
             if (check_compatible_only)
                 return (has_sps & has_pps);
         }
-        if((state&0xFFFFFF00) == 0x100 && ((state&0xFFFFFF1F) == 0x101 || (state&0xFFFFFF1F) == 0x102 || (state&0xFFFFFF1F) == 0x105)){
+        if((state&0xFFFFFF00) == 0x100
+                && ((state&0xFFFFFF1F) == 0x101
+                    || (state&0xFFFFFF1F) == 0x102
+                    || (state&0xFFFFFF1F) == 0x105)){
             if(has_pps){
                 while(i>4 && buf[i-5]==0) i--;
                 return i-4;
@@ -303,9 +290,8 @@ static int h264_split(AVCodecContext *avctx,
     return 0;
 }
 
-/* ref: libavcodec/mpegvideo_parser.c */
-static int mpegvideo_split(AVCodecContext *avctx,
-                           const uint8_t *buf, int buf_size, int check_compatible_only)
+static int mpegvideo_split(AVCodecContext *avctx __unused,
+        const uint8_t *buf, int buf_size, int check_compatible_only __unused)
 {
     int i;
     uint32_t state= -1;
@@ -323,20 +309,20 @@ static int mpegvideo_split(AVCodecContext *avctx,
 
 /* split extradata from buf for Android OMXCodec */
 int parser_split(AVCodecContext *avctx,
-                      const uint8_t *buf, int buf_size)
+        const uint8_t *buf, int buf_size)
 {
     if (!avctx || !buf || buf_size <= 0) {
-        LOGE("parser split, valid params");
+        ALOGE("parser split, valid params");
         return 0;
     }
 
-    if (avctx->codec_id == CODEC_ID_H264) {
+    if (avctx->codec_id == AV_CODEC_ID_H264) {
         return h264_split(avctx, buf, buf_size, 0);
-    } else if (avctx->codec_id == CODEC_ID_MPEG2VIDEO ||
-            avctx->codec_id == CODEC_ID_MPEG4) {
+    } else if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
+            avctx->codec_id == AV_CODEC_ID_MPEG4) {
         return mpegvideo_split(avctx, buf, buf_size, 0);
     } else {
-        LOGE("parser split, unsupport the codec, id: 0x%0x", avctx->codec_id);
+        ALOGE("parser split, unsupport the codec, id: 0x%0x", avctx->codec_id);
     }
 
     return 0;
@@ -345,18 +331,212 @@ int parser_split(AVCodecContext *avctx,
 int is_extradata_compatible_with_android(AVCodecContext *avctx)
 {
     if (avctx->extradata_size <= 0) {
-        LOGI("extradata_size <= 0, extradata is not compatible with android decoder, the codec id: 0x%0x", avctx->codec_id);
+        ALOGI("extradata_size <= 0, extradata is not compatible with "
+                "android decoder, the codec id: 0x%0x", avctx->codec_id);
         return 0;
     }
 
-    if (avctx->codec_id == CODEC_ID_H264 && avctx->extradata[0] != 1 /* configurationVersion */) {
+    if (avctx->codec_id == AV_CODEC_ID_H264
+            && avctx->extradata[0] != 1 /* configurationVersion */) {
         // SPS + PPS
-        return !!(h264_split(avctx, avctx->extradata, avctx->extradata_size, 1) > 0);
+        return !!(h264_split(avctx, avctx->extradata,
+                    avctx->extradata_size, 1) > 0);
     } else {
         // default, FIXME
         return !!(avctx->extradata_size > 0);
     }
 }
 
+//////////////////////////////////////////////////////////////////////////////////
+// packet queue
+//////////////////////////////////////////////////////////////////////////////////
+void packet_queue_init(PacketQueue *q)
+{
+    memset(q, 0, sizeof(PacketQueue));
+    q->abort_request = 1;
+}
+
+void packet_queue_destroy(PacketQueue *q)
+{
+    packet_queue_abort(q);
+    packet_queue_flush(q);
+}
+
+void packet_queue_flush(PacketQueue *q)
+{
+    AVPacketList *pkt, *pkt1;
+
+    Mutex::Autolock autoLock(q->lock);
+    for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
+        pkt1 = pkt->next;
+        av_free_packet(&pkt->pkt);
+        av_freep(&pkt);
+    }
+    q->last_pkt = NULL;
+    q->first_pkt = NULL;
+    q->nb_packets = 0;
+    q->size = 0;
+}
+
+void packet_queue_abort(PacketQueue *q)
+{
+    q->abort_request = 1;
+    Mutex::Autolock autoLock(q->lock);
+    q->cond.signal();
+}
+
+static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
+{
+    AVPacketList *pkt1;
+
+    if (q->abort_request)
+        return -1;
+
+    pkt1 = (AVPacketList *)av_malloc(sizeof(AVPacketList));
+    if (!pkt1)
+        return -1;
+    pkt1->pkt = *pkt;
+    pkt1->next = NULL;
+
+    if (!q->last_pkt)
+        q->first_pkt = pkt1;
+    else
+        q->last_pkt->next = pkt1;
+    q->last_pkt = pkt1;
+    q->nb_packets++;
+    //q->size += pkt1->pkt.size + sizeof(*pkt1);
+    q->size += pkt1->pkt.size;
+    q->cond.signal();
+    return 0;
+}
+
+int packet_queue_put(PacketQueue *q, AVPacket *pkt)
+{
+    int ret;
+
+    /* duplicate the packet */
+    if (pkt != &q->flush_pkt && av_dup_packet(pkt) < 0)
+        return -1;
+
+    q->lock.lock();
+    ret = packet_queue_put_private(q, pkt);
+    q->lock.unlock();
+
+    if (pkt != &q->flush_pkt && ret < 0)
+        av_free_packet(pkt);
+
+    return ret;
+}
+
+int packet_queue_is_wait_for_data(PacketQueue *q)
+{
+    Mutex::Autolock autoLock(q->lock);
+    return q->wait_for_data;
+}
+
+int packet_queue_put_nullpacket(PacketQueue *q, int stream_index)
+{
+    AVPacket pkt1, *pkt = &pkt1;
+    av_init_packet(pkt);
+    pkt->data = NULL;
+    pkt->size = 0;
+    pkt->stream_index = stream_index;
+    return packet_queue_put(q, pkt);
+}
+
+/* packet queue handling */
+/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
+int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
+{
+    AVPacketList *pkt1;
+    int ret = -1;
+
+    Mutex::Autolock autoLock(q->lock);
+
+    while (!q->abort_request) {
+        pkt1 = q->first_pkt;
+        if (pkt1) {
+            q->first_pkt = pkt1->next;
+            if (!q->first_pkt)
+                q->last_pkt = NULL;
+            q->nb_packets--;
+            //q->size -= pkt1->pkt.size + sizeof(*pkt1);
+            q->size -= pkt1->pkt.size;
+            *pkt = pkt1->pkt;
+            av_free(pkt1);
+            ret = 1;
+            break;
+        } else if (!block) {
+            ret = 0;
+            break;
+        } else {
+            q->wait_for_data = 1;
+            q->cond.waitRelative(q->lock, 10000000LL);
+        }
+    }
+    q->wait_for_data = 0;
+    return ret;
+}
+
+void packet_queue_start(PacketQueue *q)
+{
+    Mutex::Autolock autoLock(q->lock);
+    av_init_packet(&q->flush_pkt);
+    q->flush_pkt.data = (uint8_t *)&q->flush_pkt;
+    q->flush_pkt.size = 0;
+    q->abort_request = 0;
+    packet_queue_put_private(q, &q->flush_pkt);
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// misc
+//////////////////////////////////////////////////////////////////////////////////
+bool setup_vorbis_extradata(uint8_t **extradata, int *extradata_size,
+        const uint8_t *header_start[3], const int header_len[3])
+{
+    uint8_t *p = NULL;
+    int len = 0;
+    int i = 0;
+
+    len = header_len[0] + header_len[1] + header_len[2];
+    p = *extradata = (uint8_t *)av_mallocz(64 + len + len/255);
+    if (!p) {
+        ALOGE("oom for vorbis extradata");
+        return false;
+    }
+
+    *p++ = 2;
+    p += av_xiphlacing(p, header_len[0]);
+    p += av_xiphlacing(p, header_len[1]);
+    for (i = 0; i < 3; i++) {
+        if (header_len[i] > 0) {
+            memcpy(p, header_start[i], header_len[i]);
+            p += header_len[i];
+        }
+    }
+    *extradata_size = p - *extradata;
+
+    return true;
+}
+
+int64_t get_timestamp() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+audio_format_t to_android_audio_format(enum AVSampleFormat fmt) {
+    AVSampleFormat packed = av_get_packed_sample_fmt(fmt);
+    if (packed == AV_SAMPLE_FMT_U8)
+        return AUDIO_FORMAT_PCM_8_BIT;
+    if (packed == AV_SAMPLE_FMT_S16)
+        return AUDIO_FORMAT_PCM_16_BIT;
+    if (packed == AV_SAMPLE_FMT_S32)
+        return AUDIO_FORMAT_PCM_32_BIT;
+    if (packed == AV_SAMPLE_FMT_FLT)
+        return AUDIO_FORMAT_PCM_FLOAT;
+    return AUDIO_FORMAT_DEFAULT;
+}
+
 }  // namespace android