Recherche avancée

Médias (1)

Mot : - Tags -/MediaSPIP

Autres articles (54)

  • La file d’attente de SPIPmotion

    28 novembre 2010, par

    Une file d’attente stockée dans la base de donnée
    Lors de son installation, SPIPmotion crée une nouvelle table dans la base de donnée intitulée spip_spipmotion_attentes.
    Cette nouvelle table est constituée des champs suivants : id_spipmotion_attente, l’identifiant numérique unique de la tâche à traiter ; id_document, l’identifiant numérique du document original à encoder ; id_objet l’identifiant unique de l’objet auquel le document encodé devra être attaché automatiquement ; objet, le type d’objet auquel (...)

  • List of compatible distributions

    26 avril 2011, par

    The table below is the list of Linux distributions compatible with the automated installation script of MediaSPIP. Distribution nameVersion nameVersion number Debian Squeeze 6.x.x Debian Weezy 7.x.x Debian Jessie 8.x.x Ubuntu The Precise Pangolin 12.04 LTS Ubuntu The Trusty Tahr 14.04
    If you want to help us improve this list, you can provide us access to a machine whose distribution is not mentioned above or send the necessary fixes to add (...)

  • Websites made ​​with MediaSPIP

    2 mai 2011, par

    This page lists some websites based on MediaSPIP.

Sur d’autres sites (9392)

  • 7 Ecommerce Metrics to Track and Improve in 2024

    12 avril 2024, par Erin

    You can invest hours into market research, create the best ads you’ve ever seen and fine-tune your budgets. But the only way to really know if your digital marketing campaigns move the needle is to track ecommerce metrics.

    It’s time to put your hopes and gut feelings aside and focus on the data. Ecommerce metrics are key performance indicators that can tell you a lot about the performance of a single campaign, a traffic source or your entire marketing efforts. 

    That’s why it’s essential to understand what ecommerce metrics are, key metrics to track and how to improve them. 

    Ready to do all of the above ? Then, let’s get started.

    What are ecommerce metrics ? 

    An ecommerce metric is any metric that helps you understand the effectiveness of your digital marketing efforts and the extent to which users are taking a desired action. Most ecommerce metrics focus on conversions, which could be anything from making a purchase to subscribing to your email list.

    You need to track ecommerce metrics to understand how well your marketing efforts are working. They are essential to helping you run a cost-effective marketing campaign that delivers a return on investment. 

    For example, tracking ecommerce metrics will help you identify whether your digital marketing campaigns are generating a return on investment or whether they are actually losing money. They also help you identify your most effective campaigns and traffic sources. 

    Ecommerce metrics also help you spot opportunities for improvement both in terms of your marketing campaigns and your site’s UX. 

    For instance, you can use ecommerce metrics to track the impact on revenue of A/B tests on your marketing campaigns. Or you can use them to understand how users interact with your website and what, if anything, you can do to make it more engaging.

    What’s the difference between conversion rate and conversion value ?

    The difference between a conversion rate and a conversion value is that the former is a percentage while the latter is a monetary value. 

    There can be confusion between the terms conversion rate and conversion value. Since conversions are core metrics in ecommerce, it’s worth taking a minute to clarify. 

    Conversion rates measure the percentage of people who take a desired action on your website compared to the total number of visitors. If you have 100 visitors and one of them converts, then your conversion rate is 1%. 

    Here’s the formula for calculating your conversion rate :

    Conversion Rate (%) = (Number of conversions / Total number of visitors) × 100

    Conversion rate formula

    Using the example above :

    Conversion Rate = (1 / 100) × 100 = 1%

    Conversion value is a monetary amount you assign to each conversion. In some cases, this is the price of the product a user purchases. In other conversion events, such as signing up for a free trial, you may wish to assign a hypothetical conversion value. 

    To calculate a hypothetical conversion value, let’s consider that you have estimated the average revenue generated from a paying customer is $300. If the conversion rate from free trial to paying customer is 20%, then the hypothetical conversion value for each free trial signup would be $300 multiplied by 20%, which equals $60. This takes into account the number of free trial users who eventually become paying customers.

    So the formula for hypothetical conversion value looks like this :

    Hypothetical conversion value formula

    Hypothetical conversion value = (Average revenue per paying customer) × (Conversion rate)

    Using the values from our example :

    Hypothetical conversion value = $300 × 20% = $60

    The most important ecommerce metrics and how to track them

    There are dozens of ecommerce metrics you could track, but here are seven of the most important. 

    Conversion rate

    Conversion rate is the percentage of visitors who take a desired action. It is arguably one of the most important ecommerce metrics and a great top-level indicator of the success of your marketing efforts. 

    You can measure the conversion rate of anything, including newsletter signups, ebook downloads, and product purchases, using the following formula :

    Conversion rate

    Conversion rate = (Number of people who took action / Total number of visitors) × 100

    You usually won’t have to manually calculate your conversion rate, though. Almost every web analytics or ad platform will track the conversion rate automatically.

    Matomo, for instance, automatically tracks any conversion you set in the Goals report.

    A screenshot of Matomo's Goals report

    As you can see in the screenshot, your site’s conversions are plotted over a period of time and the conversion rate is tracked below the graph. You can change the time period to see how your conversion rate fluctuates.

    If you want to go even further, track your new visitor conversion rate to see how engaging your site is to first-time visitors. 

    Try Matomo for Free

    Get the web insights you need, without compromising data accuracy.

    No credit card required

    Cost per acquisition

    Cost per acquisition (CPA) is the average cost of acquiring a new user. You can calculate your overall CPA or you can break CPA down by email campaign, traffic source, or any other criteria. 

    Calculate CPA by dividing your total marketing cost by the number of new users you acquire.

    Cost per acquisition = Total marketing cost / Number of customers acquired

    CPA = Total marketing cost​ / Number of new users acquired 

    So if your Google Ads campaign costs €1,000 and you acquire 100 new users, your CPA is €10 (1000/100=10).

    It’s important to note that CPA is not the same as customer acquisition cost. Customer acquisition cost considers the number of paying customers. CPA looks at the number of users taking a certain action, like subscribing to a newsletter, making a purchase, or signing up for a free trial.

    Cost per acquisition is a direct measure of your marketing efforts’ effectiveness, especially when comparing CPA to average customer spend and return on ad spend. 

    If your CPA is higher than the average customer spend, your marketing campaign is profitable. If not, then you can look at ways to either increase customer spend or decrease your cost per acquisition.

    Customer lifetime value

    Customer lifetime value (CLV) is the average amount of money a customer will spend with your ecommerce brand over their lifetime. 

    Customer value is the total worth of a customer to your brand based on their purchasing behaviour. To calculate it, multiply the average purchase value by the average number of purchases. For instance, if the average purchase value is €50 and customers make 5 purchases on average, the customer value would be €250.

    Use this formula to calculate customer value :

    Customer value = Average purchase value × Average number of purchases

    Customer value = Average purchase value × Average number of purchases

    Then you can calculate customer lifetime value using the following formula :

    Customer lifetime value = Customer value * Average customer lifespan

    CLV = Customer value × Average customer lifespan

    In another example, let’s say you have a software company and customers pay you €500 per year for an annual subscription. If the average customer lifespan is 5 years, then the Customer Lifetime Value (CLV) would be €2,500.

    Customer lifetime value = €500 × 5 = €2,500

    Knowing how much potential customers are likely to spend helps you set accurate marketing budgets and optimise the price of your products. 

    Return on investment

    Return on investment (ROI) is the amount of revenue your marketing efforts generate compared to total spend. 

    It’s usually calculated as a percentage using the following formula :

    Return On Investment = (Revenue / Total Spend) x 100

    ROI = (Revenue / Total spend) × 100

    If you spend €1,000 on a paid ad campaign and your efforts bring in €5,000, then your ROI is 500% (5,000/1,000 × 100).

    With a web analytics tool like Matomo, you can quickly see the revenue generated from each traffic source and you can drill down further to compare different social media channels, search engines, referral websites and campaigns to get more granular view. 

    Revenue by channel in Matomo

    In the example above in Matomo’s Marketing Attribution feature, we can see that social networks are generating the highest amount of revenue in the year. To calculate ROI, we would need to compare the amount of investment to each channel. 

    Let’s say we invested $1,000 per year in search engine optimisation and content marketing, the return on investment (ROI) stands at approximately 2576%, based on a revenue of $26,763.48 per year. 

    Conversely, for organic social media campaigns, where $5,000 was invested and revenue amounted to $71,180.22 per year, the ROI is approximately 1323%. 

    Despite differences in revenue generation, both channels exhibit significant returns on investment, with SEO and content marketing demonstrating a much higher ROI compared to organic social media campaigns. 

    With that in mind, we might want to consider shifting our marketing budget to focus more on search engine optimisation and content marketing as it’s a greater return on investment.

    Try Matomo for Free

    Get the web insights you need, without compromising data accuracy.

    No credit card required

    Return on ad spend

    Return on ad spend (ROAS) is similar to return on investment, but it measures the profitability of a specific ad or campaign.

    Calculate ROAS using the following formula :

    Return on ad Spend = revenue / ad cost

    ROAS = Revenue / Ad cost 

    A positive ROAS means you are making money. If you generate €3 for every €1 you spend on advertising, for example, there’s no reason to turn off that campaign. If you only make €1 for every €2 you spend, however, then you need to shut down the campaign or optimise it. 

    Bounce rate

    Bounce rate is the percentage of visitors who leave your site without taking another action. Calculate it using the following formula :

    Bounce rate = (Number of visitors who bounce / Total number of visitors) * 100

    Bounce rate = (Number of visitors who bounce / Total number of visitors) × 100

    Some portion of users will always leave your site immediately, but you should aim to make your bounce rate as low as possible. After all, every customer that bounces is a missed opportunity that you may never get again. 

    You can check the bounce rate for each one of your site’s pages using Matomo’s page analytics report. Web analytics tools like Google Analytics can track bounce rates for online stores also. 

    A screenshot of Matomo's page view report A screenshot of Matomo's page view report

    Bounce rate is calculated automatically. You can sort the list of pages by bounce rate allowing you to prioritise your optimisation efforts. 

    Don’t stop there, though. Explore bounce rate further by comparing your mobile bounce rate vs. desktop bounce rate by segmenting your traffic. This will highlight whether your mobile site needs improving. 

    Try Matomo for Free

    Get the web insights you need, without compromising data accuracy.

    No credit card required

    Click-through rate

    Your clickthrough rate (CTR) tells you the number of people who click on your ads as a percentage of total impressions. You can calculate it by dividing the number of clicks your ad gets by the total number of times people see it. 

    So the formula looks like this :

    Click-through Rate = (Number of clicks / Total impressions) × 100

    CTR (%) = (Number of clicks / Total impressions​) × 100

    If an ad gets 1,000 impressions and 10 people click on it, then the CTR will be 10/1,000 × 100 = 1%

    You don’t usually need to calculate your clickthrough rate manually, however. Most ad platforms like Google Ads will automatically calculate CTR.

    What is considered a good ecommerce sales conversion rate ?

    This question is so broad it’s almost impossible to answer. The thing is, sales conversion rates vary massively depending on the conversion event and the industry. A good conversion rate in one industry might be terrible in another. 

    That being said, research shows that the average website conversion rate across all industries is 2.35%. Of course, some websites convert much better than this. The same study found that the top 25% of websites across all industries have a conversion rate of 5.31% or higher. 

    How can you improve your conversion rate ?

    Ecommerce metrics don’t just let you track your campaign’s ROI, they help you identify ways to improve your campaign. 

    Use these five tips to start improving your marketing campaign’s conversion rates today :

    Run A/B tests

    The most effective way to improve almost all of the ecommerce metrics you track is to test, test, and test again.

    A/B testing or multivariate testing compares two different versions of the same content, such as a landing page or blog post. Seeing which version performs better can help you squeeze as many conversions as possible from your website and ad campaigns. But only if you test as many things as possible. This should include :

    • Ad placement
    • Ad copy
    • CTAs
    • Headlines
    • Straplines
    • Colours
    • Design

    To create and analyse tests and their results effectively, you’ll need either an A/B testing platform or a web analytics solution like Matomo, which offers one out of the box.

    A/B testing in Matomo analytics

    Matomo’s A/B Testing feature makes it easy to create and track tests over time, breaking down each test’s variations by the metrics that matter. It automatically calculates statistical significance, too, meaning you can be sure you’re making a change for the better. 

    Try Matomo for Free

    Get the web insights you need, without compromising data accuracy.

  • Decoding and playing audio with ffmpeg and XAudio2 - frequency ratio wrong

    9 mars, par Brent de Carteret

    I'm using ffmpeg to decode audio and output it using the XAudio2 API, it works and plays synced with the video output using the pts. But it's high pitched (i.e. sounds like chipmunks).

    


    Setting breakpoints I can see it has set the correct sample rate from the audio codec in CreateSourceVoice. I'm stumped.

    


    Any help would be much appreciated.

    


    CDVDAUDIO.cpp

    


    #include "DVDAudioDevice.h"
   
HANDLE m_hBufferEndEvent;

CDVDAudio::CDVDAudio()
{
    m_pXAudio2 = NULL;
    m_pMasteringVoice = NULL;
    m_pSourceVoice = NULL;
    m_pWfx  = NULL;
    m_VoiceCallback = NULL;    
    m_hBufferEndEvent = CreateEvent(NULL, false, false, "Buffer end event");
}
    
CDVDAudio::~CDVDAudio()
{
    m_pXAudio2 = NULL;
    m_pMasteringVoice = NULL;
    m_pSourceVoice = NULL;
    m_pWfx  = NULL;
    m_VoiceCallback = NULL;
    CloseHandle(m_hBufferEndEvent);
    m_hBufferEndEvent = NULL;
}
    
bool CDVDAudio::Create(int iChannels, int iBitrate, int iBitsPerSample, bool bPasstrough)
{
    CoInitializeEx(NULL, COINIT_MULTITHREADED);
    HRESULT hr = XAudio2Create( &m_pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR);
    
    if (SUCCEEDED(hr))
    {
        m_pXAudio2->CreateMasteringVoice( &m_pMasteringVoice );
    }
    
    // Create source voice
    WAVEFORMATEXTENSIBLE wfx;
    memset(&wfx, 0, sizeof(WAVEFORMATEXTENSIBLE));
    
    wfx.Format.wFormatTag           = WAVE_FORMAT_PCM;
    wfx.Format.nSamplesPerSec       = iBitrate;//pFFMpegData->pAudioCodecCtx->sample_rate;//48000 by default
    wfx.Format.nChannels            = iChannels;//pFFMpegData->pAudioCodecCtx->channels;
    wfx.Format.wBitsPerSample       = 16;
    wfx.Format.nBlockAlign          = wfx.Format.nChannels*16/8;
    wfx.Format.nAvgBytesPerSec      = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
    wfx.Format.cbSize               = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
    wfx.Samples.wValidBitsPerSample = wfx.Format.wBitsPerSample;
    
    if(wfx.Format.nChannels == 1)
    {
        wfx.dwChannelMask = SPEAKER_MONO;
    }
    else if(wfx.Format.nChannels == 2)
    {
        wfx.dwChannelMask = SPEAKER_STEREO;
    }
    else if(wfx.Format.nChannels == 5)
    {
        wfx.dwChannelMask = SPEAKER_5POINT1;
    }
    
    wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
    
    unsigned int flags = 0;//XAUDIO2_VOICE_NOSRC;// | XAUDIO2_VOICE_NOPITCH;
        
    //Source voice
    m_VoiceCallback = new StreamingVoiceCallback(this);
    hr = m_pXAudio2->CreateSourceVoice(&m_pSourceVoice,(WAVEFORMATEX*)&wfx, 0 , 1.0f, m_VoiceCallback);
        
    if (!SUCCEEDED(hr))
        return false;
    
    // Start sound
    hr = m_pSourceVoice->Start(0);
    
    if(!SUCCEEDED(hr))
        return false;
    
    return true;
}
    
DWORD CDVDAudio::AddPackets(unsigned char* data, DWORD len)
{  
    memset(&m_SoundBuffer,0,sizeof(XAUDIO2_BUFFER));
    m_SoundBuffer.AudioBytes = len;
    m_SoundBuffer.pAudioData = data;
    m_SoundBuffer.pContext = NULL;//(VOID*)data;
    XAUDIO2_VOICE_STATE state;
    
    while (m_pSourceVoice->GetState( &state ), state.BuffersQueued > 60)
    {
        WaitForSingleObject( m_hBufferEndEvent, INFINITE );
    }
    
    m_pSourceVoice->SubmitSourceBuffer( &m_SoundBuffer );
    return 0;
}
    
void CDVDAudio::Destroy()
{
    m_pMasteringVoice->DestroyVoice();
    m_pXAudio2->Release();
    m_pSourceVoice->DestroyVoice();
    delete m_VoiceCallback;
    m_VoiceCallback = NULL;
}


    


    CDVDAUdioCodecFFmpeg.cpp

    


    #include "DVDAudioCodecFFmpeg.h"
#include "Log.h"
    
CDVDAudioCodecFFmpeg::CDVDAudioCodecFFmpeg() : CDVDAudioCodec()
{
    m_iBufferSize = 0;
    m_pCodecContext = NULL;
    m_bOpenedCodec = false;
}
    
CDVDAudioCodecFFmpeg::~CDVDAudioCodecFFmpeg()
{
    Dispose();
}
    
bool CDVDAudioCodecFFmpeg::Open(AVCodecID codecID, int iChannels, int iSampleRate)
{
    AVCodec* pCodec;
    m_bOpenedCodec = false;
    av_register_all();
    pCodec = avcodec_find_decoder(codecID);
    m_pCodecContext = avcodec_alloc_context3(pCodec);//avcodec_alloc_context();
    avcodec_get_context_defaults3(m_pCodecContext, pCodec);
    
    if (!pCodec)
    {
        CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Open() Unable to find codec");
        return false;
    }
    
    m_pCodecContext->debug_mv = 0;
    m_pCodecContext->debug = 0;
    m_pCodecContext->workaround_bugs = 1;
    
    if (pCodec->capabilities & CODEC_CAP_TRUNCATED)
        m_pCodecContext->flags |= CODEC_FLAG_TRUNCATED;
    
    m_pCodecContext->channels = iChannels;
    m_pCodecContext->sample_rate = iSampleRate;
    //m_pCodecContext->bits_per_sample = 24;
     
    /* //FIXME BRENT
        if( ExtraData && ExtraSize > 0 )
        {
            m_pCodecContext->extradata_size = ExtraSize;
            m_pCodecContext->extradata = m_dllAvCodec.av_mallocz(ExtraSize + FF_INPUT_BUFFER_PADDING_SIZE);
            memcpy(m_pCodecContext->extradata, ExtraData, ExtraSize);
        }
    */
    
    // set acceleration
    //m_pCodecContext->dsp_mask = FF_MM_FORCE | FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE; //BRENT
    
    if (avcodec_open2(m_pCodecContext, pCodec, NULL) < 0)
    {
        CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Open() Unable to open codec");
        Dispose();
        return false;
    }
    
    m_bOpenedCodec = true;
    return true;
}
    
void CDVDAudioCodecFFmpeg::Dispose()
{
    if (m_pCodecContext)
    {
        if (m_bOpenedCodec)
            avcodec_close(m_pCodecContext);
        m_bOpenedCodec = false;
        av_free(m_pCodecContext);
        m_pCodecContext = NULL;
    }
    m_iBufferSize = 0;
}

int CDVDAudioCodecFFmpeg::Decode(BYTE* pData, int iSize)
{
    int iBytesUsed;
    if (!m_pCodecContext) return -1;
    
    //Copy into a FFMpeg AVPAcket again
    AVPacket packet;
    av_init_packet(&packet);
    
    packet.data=pData;
    packet.size=iSize;
    
    int iOutputSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; //BRENT
    
    iBytesUsed = avcodec_decode_audio3(m_pCodecContext, (int16_t *)m_buffer, &iOutputSize/*m_iBufferSize*/, &packet);

    m_iBufferSize = iOutputSize;//BRENT

    return iBytesUsed;
}

int CDVDAudioCodecFFmpeg::GetData(BYTE** dst)
{
    *dst = m_buffer;
    return m_iBufferSize;
}

void CDVDAudioCodecFFmpeg::Reset()
{
    if (m_pCodecContext)
        avcodec_flush_buffers(m_pCodecContext);
}

int CDVDAudioCodecFFmpeg::GetChannels()
{
    if (m_pCodecContext)
        return m_pCodecContext->channels;
    return 0;
}

int CDVDAudioCodecFFmpeg::GetSampleRate()
{
    if (m_pCodecContext)
        return m_pCodecContext->sample_rate;
    return 0;
}
    
int CDVDAudioCodecFFmpeg::GetBitsPerSample()
{
    if (m_pCodecContext)
        return 16;
    return 0;
}


    


    CDVDPlayerAudio.cpp

    


    #include "DVDPlayerAudio.h"
#include "DVDDemuxUtils.h"
#include "Log.h"
    
#include 
#include "DVDAudioCodecFFmpeg.h" //FIXME Move to a codec factory!!
    
CDVDPlayerAudio::CDVDPlayerAudio(CDVDClock* pClock) : CThread()
{
    m_pClock = pClock;
    m_pAudioCodec = NULL;
    m_bInitializedOutputDevice = false;
    m_iSourceChannels = 0;
    m_audioClock = 0;
    
    //  m_currentPTSItem.pts = DVD_NOPTS_VALUE;
    //  m_currentPTSItem.timestamp = 0;
    
    SetSpeed(DVD_PLAYSPEED_NORMAL);
      
    InitializeCriticalSection(&m_critCodecSection);
    m_messageQueue.SetMaxDataSize(10 * 16 * 1024);
    //  g_dvdPerformanceCounter.EnableAudioQueue(&m_packetQueue);
}

CDVDPlayerAudio::~CDVDPlayerAudio()
{
    //  g_dvdPerformanceCounter.DisableAudioQueue();

    // close the stream, and don't wait for the audio to be finished
    CloseStream(true);
    DeleteCriticalSection(&m_critCodecSection);
}

bool CDVDPlayerAudio::OpenStream( CDemuxStreamAudio *pDemuxStream )
{
    // should always be NULL!!!!, it will probably crash anyway when deleting m_pAudioCodec here.
    if (m_pAudioCodec)
    {
        CLog::Log(LOGFATAL, "CDVDPlayerAudio::OpenStream() m_pAudioCodec != NULL");
        return false;
    }
    
    AVCodecID codecID = pDemuxStream->codec;
    
    CLog::Log(LOGNOTICE, "Finding audio codec for: %i", codecID);
    //m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec( pDemuxStream ); 
    m_pAudioCodec = new CDVDAudioCodecFFmpeg; //FIXME BRENT Codec Factory needed!
    
    if (!m_pAudioCodec->Open(pDemuxStream->codec, pDemuxStream->iChannels, pDemuxStream->iSampleRate))
    {
        m_pAudioCodec->Dispose();
        delete m_pAudioCodec;
        m_pAudioCodec = NULL;
        return false;
    }
    
    if ( !m_pAudioCodec )
    {
        CLog::Log(LOGERROR, "Unsupported audio codec");
        return false;
    }
    
    m_codec = pDemuxStream->codec;
    m_iSourceChannels = pDemuxStream->iChannels;
    m_messageQueue.Init();
    
    CLog::Log(LOGNOTICE, "Creating audio thread");
    Create();
    
    return true;
}

void CDVDPlayerAudio::CloseStream(bool bWaitForBuffers)
{
    // wait until buffers are empty
    if (bWaitForBuffers)
        m_messageQueue.WaitUntilEmpty();
    
    // send abort message to the audio queue
    m_messageQueue.Abort();
    
    CLog::Log(LOGNOTICE, "waiting for audio thread to exit");
    
    // shut down the audio_decode thread and wait for it
    StopThread(); // will set this->m_bStop to true
    this->WaitForThreadExit(INFINITE);
    
    // uninit queue
    m_messageQueue.End();
    
    CLog::Log(LOGNOTICE, "Deleting audio codec");
    if (m_pAudioCodec)
    {
        m_pAudioCodec->Dispose();
        delete m_pAudioCodec;
        m_pAudioCodec = NULL;
    }
    
    // flush any remaining pts values
    //FlushPTSQueue(); //FIXME BRENT
}

void CDVDPlayerAudio::OnStartup()
{
    CThread::SetName("CDVDPlayerAudio");
    pAudioPacket = NULL;
    m_audioClock = 0;
    audio_pkt_data = NULL;
    audio_pkt_size = 0;
  
    //  g_dvdPerformanceCounter.EnableAudioDecodePerformance(ThreadHandle());
}

void CDVDPlayerAudio::Process()
{
    CLog::Log(LOGNOTICE, "running thread: CDVDPlayerAudio::Process()");

    int result;
    
    // silence data
    BYTE silence[1024];
    memset(silence, 0, 1024);
    
    DVDAudioFrame audioframe;
    
    __int64 iClockDiff=0;
    while (!m_bStop)
    {
        //Don't let anybody mess with our global variables
        EnterCriticalSection(&m_critCodecSection);
        result = DecodeFrame(audioframe, m_speed != DVD_PLAYSPEED_NORMAL); // blocks if no audio is available, but leaves critical section before doing so
        LeaveCriticalSection(&m_critCodecSection);
    
        if ( result & DECODE_FLAG_ERROR ) 
        {      
            CLog::Log(LOGERROR, "CDVDPlayerAudio::Process - Decode Error. Skipping audio frame");
            continue;
        }
    
        if ( result & DECODE_FLAG_ABORT )
        {
            CLog::Log(LOGDEBUG, "CDVDPlayerAudio::Process - Abort received, exiting thread");
            break;
        }
    
        if ( result & DECODE_FLAG_DROP ) //FIXME BRENT
        {
            /*  //frame should be dropped. Don't let audio move ahead of the current time thou
                //we need to be able to start playing at any time
                //when playing backwards, we try to keep as small buffers as possible
    
                // set the time at this delay
                AddPTSQueue(audioframe.pts, m_dvdAudio.GetDelay());
            */
            if (m_speed > 0)
            {
                __int64 timestamp = m_pClock->GetAbsoluteClock() + (audioframe.duration * DVD_PLAYSPEED_NORMAL) / m_speed;
                while ( !m_bStop && timestamp > m_pClock->GetAbsoluteClock() )
                    Sleep(1);
            }
            continue;
        }
    
        if ( audioframe.size > 0 ) 
        {
            // we have successfully decoded an audio frame, open up the audio device if not already done
            if (!m_bInitializedOutputDevice)
            {
                m_bInitializedOutputDevice = InitializeOutputDevice();
            }
    
            //Add any packets play
            m_dvdAudio.AddPackets(audioframe.data, audioframe.size);
    
            // store the delay for this pts value so we can calculate the current playing
            //AddPTSQueue(audioframe.pts, m_dvdAudio.GetDelay() - audioframe.duration);//BRENT
        }
    
        // if we where asked to resync on this packet, do so here
        if ( result & DECODE_FLAG_RESYNC )
        {
            CLog::Log(LOGDEBUG, "CDVDPlayerAudio::Process - Resync recieved.");
            //while (!m_bStop && (unsigned int)m_dvdAudio.GetDelay() > audioframe.duration ) Sleep(5); //BRENT
            m_pClock->Discontinuity(CLOCK_DISC_NORMAL, audioframe.pts);
        }
    
        #ifdef USEOLDSYNC
        //Clock should be calculated after packets have been added as m_audioClock points to the 
        //time after they have been played
    
        const __int64 iCurrDiff = (m_audioClock - m_dvdAudio.GetDelay()) - m_pClock->GetClock();
        const __int64 iAvDiff = (iClockDiff + iCurrDiff)/2;
    
        //Check for discontinuity in the stream, use a moving average to
        //eliminate highfreq fluctuations of large packet sizes
        if ( ABS(iAvDiff) > 5000 ) // sync clock if average diff is bigger than 5 msec 
        {
            //Wait until only the new audio frame which triggered the discontinuity is left
            //then set disc state
            while (!m_bStop && (unsigned int)m_dvdAudio.GetBytesInBuffer() > audioframe.size )
                Sleep(5);
    
            m_pClock->Discontinuity(CLOCK_DISC_NORMAL, m_audioClock - m_dvdAudio.GetDelay());
            CLog::("CDVDPlayer:: Detected Audio Discontinuity, syncing clock. diff was: %I64d, %I64d, av: %I64d", iClockDiff, iCurrDiff, iAvDiff);
            iClockDiff = 0;
        }
        else
        {
            //Do gradual adjustments (not working yet)
            //m_pClock->AdjustSpeedToMatch(iClock + iAvDiff);
            iClockDiff = iCurrDiff;
        }
        #endif
    }
}

void CDVDPlayerAudio::OnExit()
{
    //g_dvdPerformanceCounter.DisableAudioDecodePerformance();
  
    // destroy audio device
    CLog::Log(LOGNOTICE, "Closing audio device");
    m_dvdAudio.Destroy();
    m_bInitializedOutputDevice = false;

    CLog::Log(LOGNOTICE, "thread end: CDVDPlayerAudio::OnExit()");
}

// decode one audio frame and returns its uncompressed size
int CDVDPlayerAudio::DecodeFrame(DVDAudioFrame &audioframe, bool bDropPacket)
{
    CDVDDemux::DemuxPacket* pPacket = pAudioPacket;
    int n=48000*2*16/8, len;
    
    //Store amount left at this point, and what last pts was
    unsigned __int64 first_pkt_pts = 0;
    int first_pkt_size = 0; 
    int first_pkt_used = 0;
    int result = 0;
    
    // make sure the sent frame is clean
    memset(&audioframe, 0, sizeof(DVDAudioFrame));
    
    if (pPacket)
    {
        first_pkt_pts = pPacket->pts;
        first_pkt_size = pPacket->iSize;
        first_pkt_used = first_pkt_size - audio_pkt_size;
    }
     
    for (;;)
    {
        /* NOTE: the audio packet can contain several frames */
        while (audio_pkt_size > 0)
        {
            len = m_pAudioCodec->Decode(audio_pkt_data, audio_pkt_size);
            if (len < 0)
            {
                /* if error, we skip the frame */
                audio_pkt_size=0;
                m_pAudioCodec->Reset();
                break;
            }
    
            // fix for fucked up decoders //FIXME BRENT
            if( len > audio_pkt_size )
            {        
                CLog::Log(LOGERROR, "CDVDPlayerAudio:DecodeFrame - Codec tried to consume more data than available. Potential memory corruption");        
                audio_pkt_size=0;
                m_pAudioCodec->Reset();
                assert(0);
            }
    
            // get decoded data and the size of it
            audioframe.size = m_pAudioCodec->GetData(&audioframe.data);
            audio_pkt_data += len;
            audio_pkt_size -= len;
    
            if (audioframe.size <= 0)
                continue;
    
            audioframe.pts = m_audioClock;
    
            // compute duration.
            n = m_pAudioCodec->GetChannels() * m_pAudioCodec->GetBitsPerSample() / 8 * m_pAudioCodec->GetSampleRate();
            if (n > 0)
            {
                // safety check, if channels == 0, n will result in 0, and that will result in a nice divide exception
                audioframe.duration = (unsigned int)(((__int64)audioframe.size * DVD_TIME_BASE) / n);
    
                // increase audioclock to after the packet
                m_audioClock += audioframe.duration;
            }
    
            //If we are asked to drop this packet, return a size of zero. then it won't be played
            //we currently still decode the audio.. this is needed since we still need to know it's 
            //duration to make sure clock is updated correctly.
            if ( bDropPacket )
            {
                result |= DECODE_FLAG_DROP;
            }
            return result;
        }
    
        // free the current packet
        if (pPacket)
        {
            CDVDDemuxUtils::FreeDemuxPacket(pPacket); //BRENT FIXME
            pPacket = NULL;
            pAudioPacket = NULL;
        }
    
        if (m_messageQueue.RecievedAbortRequest())
            return DECODE_FLAG_ABORT;
    
        // read next packet and return -1 on error
        LeaveCriticalSection(&m_critCodecSection); //Leave here as this might stall a while
    
        CDVDMsg* pMsg;
        MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, INFINITE);
        EnterCriticalSection(&m_critCodecSection);
            
        if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT)
            return DECODE_FLAG_ABORT;
    
        if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
        {
            CDVDMsgDemuxerPacket* pMsgDemuxerPacket = (CDVDMsgDemuxerPacket*)pMsg;
            pPacket = pMsgDemuxerPacket->GetPacket();
            pMsgDemuxerPacket->m_pPacket = NULL; // XXX, test
            pAudioPacket = pPacket;
            audio_pkt_data = pPacket->pData;
            audio_pkt_size = pPacket->iSize;
        }
        else
        {
            // other data is not used here, free if
            // msg itself will still be available
            pMsg->Release();
        }
 
        // if update the audio clock with the pts
        if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET) || pMsg->IsType(CDVDMsg::GENERAL_RESYNC))
        {
            if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC))
            { 
                //player asked us to sync on this package
                CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg;
                result |= DECODE_FLAG_RESYNC;
                m_audioClock = pMsgGeneralResync->GetPts();
            }
            else if (pPacket->pts != DVD_NOPTS_VALUE) // CDVDMsg::DEMUXER_PACKET, pPacket is already set above
            {
                if (first_pkt_size == 0) 
                { 
                    //first package
                    m_audioClock = pPacket->pts;        
                }
                else if (first_pkt_pts > pPacket->pts)
                { 
                    //okey first packet in this continous stream, make sure we use the time here        
                    m_audioClock = pPacket->pts;        
                }
                else if ((unsigned __int64)m_audioClock < pPacket->pts || (unsigned __int64)m_audioClock > pPacket->pts)
                {
                    //crap, moved outsided correct pts
                    //Use pts from current packet, untill we find a better value for it.
                    //Should be ok after a couple of frames, as soon as it starts clean on a packet
                    m_audioClock = pPacket->pts;
                }
                else if (first_pkt_size == first_pkt_used)
                {
                    //Nice starting up freshly on the start of a packet, use pts from it
                    m_audioClock = pPacket->pts;
                }
            }
        }
        pMsg->Release();
    }
}

void CDVDPlayerAudio::SetSpeed(int speed)
{ 
    m_speed = speed;
  
    //if (m_speed == DVD_PLAYSPEED_PAUSE) m_dvdAudio.Pause(); //BRENT FIXME
    //else m_dvdAudio.Resume();
}
    
bool CDVDPlayerAudio::InitializeOutputDevice()
{
    int iChannels = m_pAudioCodec->GetChannels();
    int iSampleRate = m_pAudioCodec->GetSampleRate();
    int iBitsPerSample = m_pAudioCodec->GetBitsPerSample();
    //bool bPasstrough = m_pAudioCodec->NeedPasstrough(); //BRENT
    
    if (iChannels == 0 || iSampleRate == 0 || iBitsPerSample == 0)
    {
        CLog::Log(LOGERROR, "Unable to create audio device, (iChannels == 0 || iSampleRate == 0 || iBitsPerSample == 0)");
        return false;
    }
    
    CLog::Log(LOGNOTICE, "Creating audio device with codec id: %i, channels: %i, sample rate: %i", m_codec, iChannels, iSampleRate);
    if (m_dvdAudio.Create(iChannels, iSampleRate, iBitsPerSample, /*bPasstrough*/0)) // always 16 bit with ffmpeg ? //BRENT Passthrough needed?
    {
        return true;
    }
    
    CLog::Log(LOGERROR, "Failed Creating audio device with codec id: %i, channels: %i, sample rate: %i", m_codec, iChannels, iSampleRate);
    return false;
}


    


  • How to download .m3u8 in once time

    11 octobre 2024, par Nabi K.A.Z.

    I have a .m3u8 file on remote host, with contain fixed numbers of chunk .ts file name, and not stream :

    



    #EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.736,
media_0.ts
#EXTINF:9.96,
media_1.ts
#EXTINF:10.0,
media_2.ts
#EXTINF:10.0,
media_3.ts
#EXTINF:10.0,
media_4.ts
#EXTINF:10.2,
media_5.ts
#EXTINF:10.0,


    



    When I use this command :

    



    # ffmpeg -i "http://example.com/chunklist.m3u8" file.mp4

frame=  582 fps=9.4 q=28.0 size=    1536kB time=00:00:23.21 bitrate= 542.1kbits/s dup=2 drop=4 speed=0.375x


    



    It works. But It get frame by frame video and very long time needed. (It takes time almost to playback the video.)

    



    But since the path of all the .ts files are known. (http://example.com/media_0.ts, http://example.com/media_1.ts, ...) There must be a way to get and merge them all at the same time.

    



    But How in ffmpeg directly ?!

    



    EDIT (try a solution) :

    



    For one solution, I know how can concatenation files with ffmpeg.

    



    ffmpeg -i "concat:0.ts|1.ts|2.ts|3.ts|4.ts|5.ts" -c copy output.mp4


    



    This ffmpeg command was great, and works in less 1 sec time !

    



    So try to download all .ts files with CURL with this command :

    



    curl \
http://example.com/media_0.ts -o 0.ts \
http://example.com/media_1.ts -o 1.ts \
http://example.com/media_2.ts -o 2.ts \
http://example.com/media_3.ts -o 3.ts \
http://example.com/media_4.ts -o 4.ts \
http://example.com/media_5.ts -o 5.ts


    



    But you can see result :

    



      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  687k  100  687k    0     0  75108      0  0:00:09  0:00:09 --:--:-- 74111
100  652k  100  652k    0     0  59404      0  0:00:11  0:00:11 --:--:-- 53400
100  673k  100  673k    0     0  48675      0  0:00:14  0:00:14 --:--:-- 55781
100  657k  100  657k    0     0  63573      0  0:00:10  0:00:10 --:--:-- 62494
100  671k  100  671k    0     0  39019      0  0:00:17  0:00:17 --:--:-- 40863
100  692k  100  692k    0     0  63480      0  0:00:11  0:00:11 --:--:-- 80049


    



    See, total download time was 72 sec, while the total duration of all parts is 59 sec ! that this time is very long !

    



    So sorry, download all parts and then concat that, was not good solution.

    



    EDIT 2

    



    I try for another .m3u8 file on the another server with difference URL :

    



    Download and concat together :

    



    ffmpeg -i "concat:\
http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_0.ts|\
http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_1.ts|\
http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_2.ts|\
http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_3.ts|\
http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_4.ts|\
http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_5.ts\
" -c copy -y output.ts


    



    Another command with input.txt URLs file.

    



    ffmpeg -f "concat" -i "input.txt" -c copy -y output.ts


    



    input.txt file :

    



    file 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_0.ts'
file 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_1.ts'
file 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_2.ts'
file 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_3.ts'
file 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_4.ts'
file 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_5.ts'


    



    Or this command some time if needed :

    



    ffmpeg -f "concat" -safe "0" -protocol_whitelist "file,http,https,tcp,tls" -i "input.txt" -c copy -y output.ts


    



    Finally, for that download speed was good, MAYBE my server target has limited bandwidth. :-(