EXC_BAD_ACCESS в avformat_find_stream_info в FFMPEG - PullRequest
0 голосов
/ 19 декабря 2018

Я достиг потоковой передачи IP-камеры с помощью ffmpeg с помощью этой библиотеки: https://github.com/kolyvan/kxmovie также я записываю поступающую потоковую передачу IPCamera, и то же самое делается с помощью ffmpeg.

Теперь я сталкиваюсь с одной проблемой, как только я добавляю R5ProStreaming.framework в проект и запускаю приложение в реальном устройстве, приложение падает на if (avformat_find_stream_info(formatCtx, NULL) < 0) здесь.И когда я удаляю этот фреймворк и перемещаю его в мусорную корзину и снова запускаю, тогда все работает нормально.

- (kxMovieError) openInput: (NSString *) path
{
    AVFormatContext *formatCtx = NULL;

    if (_interruptCallback) {

        formatCtx = avformat_alloc_context();
        if (!formatCtx)
            return kxMovieErrorOpenFile;

        AVIOInterruptCB cb = {interrupt_callback, (__bridge void *)(self)};
        formatCtx->interrupt_callback = cb;
    }
    AVDictionary *opts = 0;
//
    av_dict_set(&opts, "rtsp_transport", "tcp", 0);

    if (avformat_open_input(&formatCtx, [path cStringUsingEncoding: NSUTF8StringEncoding], NULL,  &opts) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Couldn't open file\n");
        return kxMovieErrorStreamInfoNotFound;


    }
        if (avformat_open_input(&formatCtx, [path cStringUsingEncoding: NSUTF8StringEncoding], NULL, NULL) < 0) {

        if (formatCtx)
            avformat_free_context(formatCtx);
        return kxMovieErrorOpenFile;
    }

    //-----APP IS GETTING CRASHED HERE AND GIVING EXC_BAD_ACCESS---//
    if (avformat_find_stream_info(formatCtx, NULL) < 0)
    {
        avformat_close_input(&formatCtx);
        return kxMovieErrorStreamInfoNotFound;
    }
//
    av_dump_format(formatCtx, 0, [path.lastPathComponent cStringUsingEncoding: NSUTF8StringEncoding], false);

    _formatCtx = formatCtx;

    inputFormatCtx = _formatCtx;
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"newdemo" ofType:@".mov"];

    if (filePath)
    {
        NSLog(@"%s - %d # File found", __PRETTY_FUNCTION__, __LINE__);
    }
    else
    {
        NSLog(@"%s - %d # File NOT found", __PRETTY_FUNCTION__, __LINE__);
    }

    /*
     *  av_find_input_format(const char *short_name)
     *
     *  Find AVInputFormat based on the short name of the input format.
     */
    AVInputFormat *inputFormat = av_find_input_format([@"mpeg" UTF8String]);

    if (inputFormat)
    {
        NSLog(@"%s - %d # inputFormat identifed", __PRETTY_FUNCTION__, __LINE__);
    }
    else
    {
        NSLog(@"%s - %d # inputFormat NOT identifed", __PRETTY_FUNCTION__, __LINE__) ;
    }

    const char *utf8FilePath = [filePath UTF8String];
    NSLog(@"%s - %d # utf8FilePath = %s", __PRETTY_FUNCTION__, __LINE__, utf8FilePath);

    /*
     *  avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
     *
     *  Open an input stream and read the header. The codecs are not opened.
     */
    int openInputValue =0;
    NSLog(@"%s - %d # openInputValue = %d", __PRETTY_FUNCTION__, __LINE__, openInputValue);

    if (openInputValue == 0)
    {
        NSLog(@"%s - %d # Can open the file", __PRETTY_FUNCTION__, __LINE__);
    }
    else
    {
        NSLog(@"%s - %d # Cannot open the file", __PRETTY_FUNCTION__, __LINE__);
        avformat_close_input(&inputFormatCtx);
    }

    /*
     *  Read packets of a media file to get stream information.
     *
     *  avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
     */
    //    int streamInfoValue = avformat_find_stream_info(inputFormatCtx, NULL);
    //    NSLog(@"%s - %d # streamInfoValue = %d", __PRETTY_FUNCTION__, __LINE__, streamInfoValue);
    //
    //    if (streamInfoValue < 0)
    //    {
    //        NSLog(@"%s - %d # streamInfoValue Error", __PRETTY_FUNCTION__, __LINE__);
    //        avformat_close_input(&inputFormatCtx);
    //    }

    /*
     *  nb_streams : Number of Audio and Video streams of the input file
     */

    NSUInteger inputStreamCount = inputFormatCtx->nb_streams;
    NSLog(@"%s - %d # inputStreamCount = %lu", __PRETTY_FUNCTION__, __LINE__, (unsigned long)inputStreamCount);

    for(unsigned int i = 0; i<inputStreamCount; i++)
    {
        if(inputFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            NSLog(@"%s - %d # Found Video Stream", __PRETTY_FUNCTION__, __LINE__);
            inputVideoStreamIndex = i;
            inputVideoStream = inputFormatCtx->streams[i];
        }

        if(inputFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            NSLog(@"%s - %d # Found Audio Stream", __PRETTY_FUNCTION__, __LINE__);
            inputAudioStreamIndex = i;
            inputAudioStream = inputFormatCtx->streams[i];
        }
    }

    if(inputVideoStreamIndex == -1 && inputAudioStreamIndex == -1)
    {
        NSLog(@"%s - %d # Have not found any Video or Audio stream", __PRETTY_FUNCTION__, __LINE__);
    }

    /*
     *  Finding duration of the stream
     */
    if(inputFormatCtx->duration == AV_NOPTS_VALUE)
    {
        NSLog(@"%s - %d # Undefined timestamp value", __PRETTY_FUNCTION__, __LINE__);

        if(_videoStream != -1 && inputFormatCtx->streams[_videoStream])
        {
            //            if(inputFormatCtx->streams[_videoStream]->duration != AV_NOPTS_VALUE)
            //            {
            inputEndtimeInt64 = (inputFormatCtx->streams[_videoStream]->duration)/(inputFormatCtx->streams[_videoStream]->time_base.den/inputFormatCtx->streams[_videoStream]->time_base.num);
            //            }
            //            else
            //            {
            //                inputEndtimeInt64 = (inputFormatCtx->duration)/(AV_TIME_BASE);
            //
            //            }
        }
        else if(_audioStream != -1 && inputFormatCtx->streams[_audioStream])
        {
            //            if(inputFormatCtx->streams[_audioStream]->duration != AV_NOPTS_VALUE)
            //            {
            inputEndtimeInt64 = (inputFormatCtx->streams[_audioStream]->duration)/(AV_TIME_BASE);
            //            }
            //            else
            //            {
            //                inputEndtimeInt64 = (inputFormatCtx->duration)/(AV_TIME_BASE);
            //
            //            }
        }
    }
    else
    {
        NSLog(@"%s - %d # Defined timestamp value", __PRETTY_FUNCTION__, __LINE__);

        inputEndtimeInt64 = (inputFormatCtx->duration)/(AV_TIME_BASE);
    }
    NSLog(@"%s - %d # inputEndtimeInt64 = %lld", __PRETTY_FUNCTION__, __LINE__, inputEndtimeInt64);

    /*
     *  Finding out the frame rate
     */
    if(_videoStream != -1 && inputFormatCtx->streams[_videoStream])
    {

        framesPerSec =  (inputFormatCtx->streams[_videoStream]->r_frame_rate.num)/ (inputFormatCtx->streams[_videoStream]->r_frame_rate.den);
    }
    else
    {
        framesPerSec = 24;
    }

    numberOfFrames = framesPerSec * (int) inputEndtimeInt64;
    NSLog(@"%s - %d # numberOfFrames = %d", __PRETTY_FUNCTION__, __LINE__, numberOfFrames);


    /*
     *  Seek to timestamp ts.
     *
     *  avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
     */

    if(avformat_seek_file(inputFormatCtx, inputAudioStreamIndex, INT64_MIN, outputStartTimeInt64, INT64_MAX, AVSEEK_FLAG_FRAME) < 0)
    {
        NSLog(@"%s - %d # Seek OK", __PRETTY_FUNCTION__, __LINE__);
    }
    else
    {
        NSLog(@"%s - %d # Seek ERROR", __PRETTY_FUNCTION__, __LINE__);
    }

    /*
     *  Creating output file path1
     */

//    NSString * timestamp = [NSString stringWithFormat:@"%f",[[NSDate date] timeIntervalSince1970] * 1000];
//    
//    NSArray *directoryPathsArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//    NSString *documentsDirectory = [directoryPathsArray objectAtIndex:0];
//    NSString *outputFilePath = [NSString stringWithFormat:@"%@/%@.mov",documentsDirectory,timestamp]; // Not working if we replace .avi with .mp4

    NSString* filename = [NSString stringWithFormat:@"IPCamera%d.mov", _currentFile];
    NSString* outputFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
    _url = [NSURL fileURLWithPath:outputFilePath];

    /*
     *  Return the output format in the list of registered output formats
     *  which best matches the provided parameters, or return NULL if
     *  there is no match.
     *
     *  av_guess_format(const char *short_name, const char *filename, const char *mime_type)
     */
    outputFormat = av_guess_format(NULL, [outputFilePath UTF8String], NULL);

    NSLog(@"%s - %d # outputFormat->name = %s", __PRETTY_FUNCTION__, __LINE__, outputFormat->name);

    if(outputFormat == NULL)
    {
        NSLog(@"%s - %d # outputFormat == NULL", __PRETTY_FUNCTION__, __LINE__);
    }
    else
    {
        /*
         *  Allocate an AVFormatContext.
         */
        outputContext = avformat_alloc_context();

        if(outputContext)
        {
            outputContext->oformat = outputFormat;      // The output container format.

            snprintf(outputContext->filename, sizeof(outputContext->filename), "%s", [outputFilePath UTF8String]);
        }
        else
        {
            NSLog(@"%s - %d # outputContext == NULL", __PRETTY_FUNCTION__, __LINE__);
        }
    }

    outputVideoCodec = outputAudioCodec = NULL;

    /*
     *  video_codec = default video codec
     */
    if(outputFormat->video_codec != AV_CODEC_ID_NONE && inputVideoStream != NULL)
    {
        /*
         *  Find a registered encoder with a matching codec ID.
         *
         *  avcodec_find_encoder(enum AVCodecID id)
         */
        outputVideoCodec = avcodec_find_encoder(outputFormat->video_codec);

        if(NULL == outputVideoCodec)
        {
            NSLog(@"%s - %d # Could Not Find Vid Encoder", __PRETTY_FUNCTION__, __LINE__);
        }
        else
        {
            NSLog(@"%s - %d # Found Out Vid Encoder", __PRETTY_FUNCTION__, __LINE__);

            /*
             *  Add a new stream to a media file.
             *
             *  avformat_new_stream(AVFormatContext *s, const AVCodec *c)
             */
            outputVideoStream = avformat_new_stream(outputContext, outputVideoCodec);

            if(NULL == outputVideoStream)
            {
                NSLog(@"%s - %d # Failed to Allocate Output Vid Strm", __PRETTY_FUNCTION__, __LINE__);
            }
            else
            {
                NSLog(@"%s - %d # Allocated Video Stream", __PRETTY_FUNCTION__, __LINE__);

                /*
                 *  Copy the settings of the source AVCodecContext into the destination AVCodecContext.
                 *
                 *  avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
                 */

                if(avcodec_copy_context(outputVideoStream->codec, inputFormatCtx->streams[inputVideoStreamIndex]->codec) != 0)
                {
                    NSLog(@"%s - %d # Failed to Copy Context", __PRETTY_FUNCTION__, __LINE__);
                }
                else
                {
                    AVStream *st = _formatCtx->streams[_videoStream];
                    outputVideoStream->sample_aspect_ratio.den = outputVideoStream->codec->sample_aspect_ratio.den;     // denominator
                    outputVideoStream->sample_aspect_ratio.num = st->codec->sample_aspect_ratio.num;    // numerator
                    NSLog(@"%s - %d # Copied Context 1", __PRETTY_FUNCTION__, __LINE__);
                    outputVideoStream->codec->codec_id = st->codec->codec_id;
                    outputVideoStream->codec->time_base.num = st->codec->time_base.num;
                    outputVideoStream->codec->time_base.den = STREAM_FRAME_RATE;
                    outputVideoStream->time_base.num = st->time_base.num;
                    outputVideoStream->time_base.den =  st->time_base.den;
                    outputVideoStream->r_frame_rate.num =st->r_frame_rate.num;
                    outputVideoStream->nb_frames = STREAM_NB_FRAMES;
                    outputVideoStream->r_frame_rate.den = st->r_frame_rate.den;
                    outputVideoStream->avg_frame_rate.den = st->avg_frame_rate.num;
                    outputVideoStream->avg_frame_rate.num = st->avg_frame_rate.num;
//                  outputVideoStream->duration = st->duration;
                }
            }
        }
    }

    if(outputFormat->audio_codec != AV_CODEC_ID_NONE && inputAudioStream != NULL)
    {
        outputAudioCodec = avcodec_find_encoder(outputFormat->audio_codec);

        if(NULL == outputAudioCodec)
        {
            NSLog(@"%s - %d # Could Not Find Out Aud Encoder", __PRETTY_FUNCTION__, __LINE__);
        }
        else
        {
            NSLog(@"%s - %d # Found Out Aud Encoder", __PRETTY_FUNCTION__, __LINE__);

            outputAudioStream = avformat_new_stream(outputContext, outputAudioCodec);

            if(NULL == outputAudioStream)
            {
                NSLog(@"%s - %d # Failed to Allocate Out Vid Strm", __PRETTY_FUNCTION__, __LINE__);
            }
            else
            {
                if(avcodec_copy_context(outputAudioStream->codec, inputFormatCtx->streams[inputAudioStreamIndex]->codec) != 0)
                {
                    NSLog(@"%s - %d # Failed to Copy Context", __PRETTY_FUNCTION__, __LINE__);
                }
                else
                {
                    //                    AVStream *st = _formatCtx->streams[_audioStream];

                    NSLog(@"%s - %d # Copied Context 2", __PRETTY_FUNCTION__, __LINE__);
                    outputAudioStream->codec->codec_id = inputAudioStream->codec->codec_id;
                    outputAudioStream->codec->codec_tag = 0;
                    //                    outputAudioStream->pts = inputAudioStream->pts;
//                    outputAudioStream->duration = inputAudioStream->duration;
                    outputAudioStream->time_base.num = inputAudioStream->time_base.num;
                    outputAudioStream->time_base.den = inputAudioStream->time_base.den;
                }
            }
        }
    }

    if (!(outputFormat->flags & AVFMT_NOFILE))
    {
        /*
         *  Create and initialize a AVIOContext for accessing the resource indicated by url.
         *
         *  avio_open2(AVIOContext **s, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
         */
        if (avio_open2(&outputContext->pb, [outputFilePath UTF8String], AVIO_FLAG_WRITE, NULL, NULL) < 0)
        {
            NSLog(@"%s - %d # Could Not Open File", __PRETTY_FUNCTION__, __LINE__);
        }
    }

    /* Write the stream header, if any. */
    /*
     *  Allocate the stream private data and write the stream header to an output media file.
     *
     *  avformat_write_header(AVFormatContext *s, AVDictionary **options);
     */
    if (avformat_write_header(outputContext, NULL) < 0)
    {
        NSLog(@"%s - %d # Error Occurred While Writing Header", __PRETTY_FUNCTION__, __LINE__);
    }
    else
    {
        NSLog(@"%s - %d # Written Output header", __PRETTY_FUNCTION__, __LINE__);

        initDone = true;
    }

    return kxMovieErrorNone;
}

Более того, я связался с командой Red5Pro и спросил их об этом вместе с демонстрацией видео.Они ответили мне так:

Скорее всего, происходит то, что загружаемая этим проектом версия FFMPEG несовместима с его настроенной версией, встроенной в наш SDK, и с некоторыми дубликатами.ошибка определения приводит к загрузке неверной версии.Также может быть любое количество конфликтов между одной из библиотек в этом проекте с SDK или одной из вспомогательных библиотек, которые требуются для sdk (я должен предположить, что с момента компиляции вы добавили библиотеки, перечисленные в шаге 4здесь: https://www.red5pro.com/docs/streaming/ios.html#project-setup) и, если это так, я не знаю хорошего способа исправить проблему, так как поиск отдельных сторонних библиотек, которые повышают несовместимость с нашими SDK для их исправления, недоступенНаша команда.(отредактировано)

Кто-нибудь может представить, где искать?

Спасибо

1 Ответ

0 голосов
/ 27 декабря 2018

Запрос исходного кода для настроенной версии FFMPEG, встроенной в Red5Pro SDK.Используйте эту версию в своем коде, чтобы устранить несовместимости.Они обязаны предоставить вам измененный исходный код в соответствии с лицензией GPL / LGPL FFMPEG.

...