Beispiel #1
0
    std::shared_ptr<pipeline_profile> pipeline_config::resolve(std::shared_ptr<pipeline> pipe)
    {
        std::lock_guard<std::mutex> lock(_mtx);
        _resolved_profile.reset();
        auto requested_device = resolve_device_requests(pipe);

        std::vector<stream_profile> resolved_profiles;

        //if the user requested all streams, or if the requested device is from file and the user did not request any stream
        if (_enable_all_streams || (!_device_request.filename.empty() && _stream_requests.empty()))
        {
            if (!requested_device)
            {
                requested_device = get_first_or_default_device(pipe);
            }

            util::config config;
            config.enable_all(util::best_quality);
            _resolved_profile = std::make_shared<pipeline_profile>(requested_device, config, _device_request.record_output);
            return _resolved_profile;
        }
        else
        {
            util::config config;

            //If the user did not request anything, give it the default
            if (_stream_requests.empty())
            {
                if (!requested_device)
                {
                    requested_device = get_first_or_default_device(pipe);
                }

                auto default_profiles = get_default_configuration(requested_device);
                for (auto prof : default_profiles)
                {
                    auto p = dynamic_cast<video_stream_profile*>(prof.get());
                    if (!p)
                    {
                        LOG_ERROR("prof is not video_stream_profile");
                        throw std::logic_error("Failed to resolve request. internal error");
                    }
                    config.enable_stream(p->get_stream_type(), p->get_stream_index(), p->get_width(), p->get_height(), p->get_format(), p->get_framerate());
                }

                _resolved_profile = std::make_shared<pipeline_profile>(requested_device, config, _device_request.record_output);
                return _resolved_profile;
            }
            else
            {
                //User enabled some stream, enable only them   
                for(auto&& req : _stream_requests)
                {
                    auto r = req.second;
                    config.enable_stream(r.stream, r.stream_index, r.width, r.height, r.format, r.fps);
                }

                auto devs = pipe->get_context()->query_devices();
                if (devs.empty())
                {
                    auto dev = get_first_or_default_device(pipe);
                    _resolved_profile = std::make_shared<pipeline_profile>(dev, config, _device_request.record_output);
                    return _resolved_profile;
                }
                else
                {
                    for (auto dev_info : devs)
                    {
                        try
                        {
                            auto dev = dev_info->create_device();
                            _resolved_profile = std::make_shared<pipeline_profile>(dev, config, _device_request.record_output);
                            return _resolved_profile;
                        }
                        catch (...) {}
                    }
                }

                throw std::runtime_error("Failed to resolve request. No device found that satisfies all requirements");
            }
        }

        assert(0); //Unreachable code
    }
Beispiel #2
0
void *process_stream (void *args_) {
    // puts("_");
    Thread_param *params = (Thread_param *) args_;

    if (params->delay_ms) {
        assert(params->delay_ms >= 0 && params->delay_ms <= 999);
        // fprinttfn(stderr, "gonna sleep %ims", params->delay_ms);
        timespec_ sleep_time;
        sleep_time.tv_sec = 0;
        sleep_time.tv_nsec = params->delay_ms * 1000000;
        assert(! nanosleep(&sleep_time, NULL));
    }

    fprinttfn(stdout, "@starting_thread %i", params->id);

    // timespec_ start_time;
    // assert(clock_gettime(CLOCK_MONOTONIC, &start_time) == 0);

    AVFormatContext *av_context = NULL;
    // puts("((");
    // fprintf(stderr, "str: %s\n", params->rtmp_string);
    // puts("))");
    // pthread_mutex_lock(&mt);
    // puts("1");
    int err = avformat_open_input(&av_context, params->rtmp_string, NULL, NULL); 
    // puts("2");
    // pthread_mutex_unlock(&mt);
    if (err != 0) {
        av_strerror(err, errbuf, ERRBUF_SZ);
        // fprintf(stderr, "avformat_open_input() failed: %s\n", errbuf);
        fprinttfn(stdout, "@error avformat_open_input() fail: %s", errbuf);
        // exit(EXIT_FAILURE);

        //TODO review
        fprinttfn(stdout, "@stopping_thread failed to open stream");
        // avformat_close_input(&av_context);
        pthread_exit(NULL);
    }

    //***NetStream.Timestamp shows in log here already

    //*** it reads several frames
    // pthread_mutex_lock(&mt);
    err = avformat_find_stream_info(av_context, NULL);
    // pthread_mutex_unlock(&mt);
    if (err < 0) {
        av_strerror(err, errbuf, ERRBUF_SZ);
        fprintf(stderr, "avformat_find_stream_info() failed: %s\n", errbuf);
        exit(EXIT_FAILURE);
    }

    /* Dump information about file onto standard error */
    // av_dump_format(av_context, 0, "t.flv", false);

    int videoStream = get_stream_index(av_context);


    // int buffered_frame_num = 0;
    bool is_first_frame = true;
    counter_thread_param_t cparam;

    AVPacket packet;
    av_init_packet(&packet);

    // timespec_ start_time;
    // assert(clock_gettime(CLOCK_MONOTONIC, &start_time) == 0);

    /*
    So we read the frames, accumulate the numbers and check passed time. When N seconds has passed, we subtract
    FPS * N from accumulated frame number implying a "player" consumes FPS and there should be >= FPS frames in buffer each second
    */

    

    //"For video, the packet contains exactly one frame"
    //"This function returns what is stored in the file, and does not validate that what is there are valid frames for the decoder.
    //It will split what is stored in the file into frames and return one for each call.
    //It will not omit invalid data between valid frames so as to give the decoder the maximum information possible for decoding"
    while ((err = av_read_frame(av_context, &packet)) == 0) {
        if (packet.stream_index == videoStream) {
            if (is_first_frame) {
                is_first_frame = false;

                timespec_ first_frame_time = get_time();
                timespec_ first_frame_latency = subtract_timespec(first_frame_time, connected_time);
                fprinttfn(stdout, "@first_frame %ld %ld", first_frame_latency.tv_sec, first_frame_latency.tv_nsec);

                // if (params->is_live && (! got_timestamp)) {
                //     fprinttfn(stdout, "@error not_live");
                // }


                pthread_t thr;
                pthread_mutex_init(&(cparam.mutex), NULL);
                cparam.frame_num = 0;
                cparam.should_stop = false;
                pthread_attr_t attributes;
                pthread_attr_init(&attributes);
                pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
                int r = pthread_create(&thr, &attributes, track_fps, (void *) &cparam);
                if (r) {
                    fprintf(stderr, "failed to create track_fps thread: %i\n", r);
                    exit(EXIT_FAILURE);
                }
                assert(pthread_attr_destroy(&attributes) == 0);
            }

            // timespec_ cur_time;
            // assert(clock_gettime(CLOCK_MONOTONIC, &cur_time) == 0);
            // timespec_ time_passed = subtract_timespec(cur_time, start_time);

            // fprinttfn(stdout, "@frame");
            
            pthread_mutex_lock(&(cparam.mutex));
            cparam.frame_num++;
            pthread_mutex_unlock(&(cparam.mutex));
            // buffered_frame_num++;

            // if (time_passed.tv_sec > 0) {
            //     buffered_frame_num -= time_passed.tv_sec * FPS;
            //     //TODO !!! time_passed.tv_nsec

            //     // fprinttfn(stdout, "@buffered_frame_num %i", buffered_frame_num);

            //     start_time = cur_time;

            //     // if (buffered_frame_num < 0) {
            //     //     fprinttfn(stdout, "@underrun %i", buffered_frame_num);
            //     // }
            // }
        }

        av_free_packet(&packet);
        // av_init_packet(&packet); //? -- there's no call in http://libav.org/doxygen/master/pktdumper_8c_source.html but there is in some snippets
    }

    av_strerror(err, errbuf, ERRBUF_SZ);

    pthread_mutex_lock(&(cparam.mutex));
    cparam.should_stop = true;
    pthread_mutex_unlock(&(cparam.mutex));

    fprinttfn(stdout, "@stopping_thread %s", errbuf);  //timeout in rtmp string leads to "End of file"

    avformat_close_input(&av_context);

    pthread_exit(NULL);
}