static av_cold int read_header(AVFormatContext *ctx)
{
    CDIOContext *s = ctx->priv_data;
    AVStream *st;
    int ret, i;
    char *err = NULL;

    if (!(st = avformat_new_stream(ctx, NULL)))
        return AVERROR(ENOMEM);
    s->drive = cdio_cddap_identify(ctx->filename, CDDA_MESSAGE_LOGIT, &err);
    if (!s->drive) {
        av_log(ctx, AV_LOG_ERROR, "Could not open drive %s.\n", ctx->filename);
        return AVERROR(EINVAL);
    }
    if (err) {
        av_log(ctx, AV_LOG_VERBOSE, "%s\n", err);
        free(err);
    }
    if ((ret = cdio_cddap_open(s->drive)) < 0 || !s->drive->opened) {
        av_log(ctx, AV_LOG_ERROR, "Could not open disk in drive %s.\n", ctx->filename);
        return AVERROR(EINVAL);
    }

    cdio_cddap_verbose_set(s->drive, CDDA_MESSAGE_LOGIT, CDDA_MESSAGE_LOGIT);
    if (s->speed)
        cdio_cddap_speed_set(s->drive, s->speed);

    s->paranoia = cdio_paranoia_init(s->drive);
    if (!s->paranoia) {
        av_log(ctx, AV_LOG_ERROR, "Could not init paranoia.\n");
        return AVERROR(EINVAL);
    }
    cdio_paranoia_modeset(s->paranoia, s->paranoia_mode);

    st->codec->codec_type      = AVMEDIA_TYPE_AUDIO;
    if (s->drive->bigendianp)
        st->codec->codec_id    = AV_CODEC_ID_PCM_S16BE;
    else
        st->codec->codec_id    = AV_CODEC_ID_PCM_S16LE;
    st->codec->sample_rate     = 44100;
    st->codec->channels        = 2;
    if (s->drive->audio_last_sector != CDIO_INVALID_LSN &&
        s->drive->audio_first_sector != CDIO_INVALID_LSN)
        st->duration           = s->drive->audio_last_sector - s->drive->audio_first_sector;
    else if (s->drive->tracks)
        st->duration = s->drive->disc_toc[s->drive->tracks].dwStartSector;
    avpriv_set_pts_info(st, 64, CDIO_CD_FRAMESIZE_RAW, 2*st->codec->channels*st->codec->sample_rate);

    for (i = 0; i < s->drive->tracks; i++) {
        char title[16];
        snprintf(title, sizeof(title), "track %02d", s->drive->disc_toc[i].bTrack);
        avpriv_new_chapter(ctx, i, st->time_base, s->drive->disc_toc[i].dwStartSector,
                       s->drive->disc_toc[i+1].dwStartSector, title);
    }

    s->last_sector = cdio_cddap_disc_lastsector(s->drive);

    return 0;
}
Beispiel #2
0
static PyObject*
CDDA_set_speed(cdio_CDDAObject* self, PyObject *args)
{
    int new_speed;

    if (!PyArg_ParseTuple(args, "i", &new_speed))
        return NULL;

    cdio_cddap_speed_set(self->cdrom_drive, new_speed);

    Py_INCREF(Py_None);
    return Py_None;
}
static void *cdromreader_thread(void *threadarg)
{
    int nreturn=0, nrsectors, nrstartsector, nrsectorsread, nrtotalsectorsread;
    struct resource_struct *resource, *device_resource;
    struct local_cdrom_struct *cdrom;
    struct audio_track_struct *audio_track;
    struct cached_block_struct *cached_block;
    struct read_call_struct *read_call;
    unsigned char tries1, tries2;
    bool foundincache, cachetested;
    struct read_command_struct *read_command=NULL;
    struct read_command_struct *read_command_again=NULL;
    char *buffread, *buffer;
    unsigned char cachereadlock;


    logoutput("CDROMREADER");


    pthread_mutex_init(&queue_lockmutex, NULL);
    pthread_cond_init(&queue_lockcond, NULL);


    while (1) {

	// wait for something on the queue and free to lock

	pthread_mutex_lock(&queue_lockmutex);

	while ( queue_lock==1 || ! head_queue_read_commands) {

	    pthread_cond_wait(&queue_lockcond, &queue_lockmutex);

	}

	// set it to locked

	queue_lock=1;


	// queue is not empty: process the read command
	// first get the read request (to read cached_block)

	read_command=head_queue_read_commands;

	// remove from queue

	head_queue_read_commands=read_command->next;
	if ( tail_queue_read_commands == read_command ) tail_queue_read_commands=head_queue_read_commands;
	if ( head_queue_read_commands ) head_queue_read_commands->prev=NULL;

	queue_lock=0;

	pthread_cond_broadcast(&(queue_lockcond));
	pthread_mutex_unlock(&(queue_lockmutex)); /* release the queue */

	// really detach from the queue
	read_command->next=NULL;
	read_command->prev=NULL;

	// process the read request
	// first find out which file to write to
	// TODO: no read_call when a read ahead

        if ( read_command->readaheadpolicy==READAHEAD_POLICY_NONE ) {

            // not initiated for read ahead purposes
            // so there must be a read_call

            read_call=read_command->read_call;

            if ( ! read_call ) {

                free(read_command);
		read_command=NULL;
                logoutput2("error!! original read call not found....");
                continue;

            }

        }

        //
        // determine the track/resource
        //

	resource=read_command->resource;

	if ( ! resource ) {

	    logoutput2("error!! audio_track not found!! serious io error");
	    continue;

	}

	audio_track=(struct audio_track_struct *) resource->data;

        foundincache=false;
        cachetested=false;
        read_command_again=NULL;
        cached_block=NULL;

        //
        // a read lock on the cache for this file/track
        //

        nreturn=try2increaseactions(resource);

        if ( nreturn<0 ) {

	    logoutput2("error!! not able to get read lock audio_track for track %i!! serious io error", read_call->tracknr);

            // what to do here??? try again?

        } else {

            cachereadlock=(unsigned char) nreturn;

        }

        while ( ! cachetested ) {


            if ( ! cached_block ) {

                // get the first cached block...

                cached_block=get_first_cached_block_internal(audio_track, read_command->startsector, read_command->endsector);

            } else {

                cached_block=cached_block->next;

            }


            if ( ! cached_block ) {

                // nothing found in cache
                break;

            } else if ( cached_block->startsector<=read_command->startsector ) {

                // a cached block found, with startsector left of the desired sector
                // check the endsector

                if ( cached_block->endsector >= read_command->endsector ) {

                    // read_command->(startsector,endsector) is in cache

                    foundincache=true;
                    break;

                } else {

                    //
                    // check the next interval right of cached_block->endsector
                    //
                    // right of cached_block->endsector is not in cache
                    // correct the read command

                    read_command->startsector=cached_block->endsector+1;
                    continue;

                }


            } else {

                // cached_block->startsector>tmpsector

                if ( cached_block->startsector>read_command->endsector ) {

                    // the cached block found doesn't offer anything
                    // so the interval has to be read

	            break;


                } else {

                    // cached_block->startsector<=read_command->endsector

                    if ( cached_block->endsector<read_command->endsector ) {

                        read_command_again=get_read_command();

                        if ( read_command_again ) {

                            read_command_again->read_call=read_command->read_call;
                            read_command_again->resource=resource;

                            read_command_again->startsector=cached_block->endsector+1;
                            read_command_again->endsector=read_command->endsector;

                            read_command_again->readaheadlevel=read_command->readaheadlevel;
                            read_command_again->readaheadpolicy=read_command->readaheadpolicy;

                        }

                    }

                    read_command->endsector=cached_block->startsector-1;
                    break;


                }

            }

        }

	decreaseactions(resource, cachereadlock);

        // readahead
        // put more read_commands in the queue
        // if there is read_command_again (created above) use that


        if ( read_command->readaheadpolicy==READAHEAD_POLICY_PIECE || read_command->readaheadpolicy==READAHEAD_POLICY_WHOLE ) {

            logoutput2("cdromreader: readahead");

    	    if ( ! read_command_again ) {

                if ( read_command->endsector<audio_track->lastsector ) {

                    // create only when there is some space left over
                    // to readahead

                    if ( read_command->readaheadpolicy==READAHEAD_POLICY_PIECE ) {

                        if ( read_command->readaheadlevel > 0 ) {

                            // read ahead for a piece
                            // and do this only when level>0

                            read_command_again=get_read_command();

                            if ( read_command_again ) {

                                read_command_again->read_call=NULL;
                                read_command_again->resource=resource;

                                read_command_again->startsector=read_command->endsector+1;
                                read_command_again->endsector=read_command_again->startsector+READAHEAD_POLICY_PIECE_SECTORS;

                                read_command_again->readaheadpolicy=READAHEAD_POLICY_PIECE;
                                read_command_again->readaheadlevel=read_command->readaheadlevel-1;


                            }

                        }

                    } else if ( read_command->readaheadpolicy==READAHEAD_POLICY_WHOLE ) {

                        read_command_again=get_read_command();

                        if ( read_command_again ) {

                            read_command_again->read_call=NULL;
                            read_command_again->resource=resource;

                            read_command_again->startsector=read_command->endsector+1;
                            read_command_again->endsector=read_command_again->startsector+READAHEAD_POLICY_WHOLE_SECTORS;

                            read_command_again->readaheadpolicy=READAHEAD_POLICY_WHOLE;
                            read_command_again->readaheadlevel=read_command->readaheadlevel;

                        }

                    }

                }


            } else {

                // there is already a read_command_again
                // adjust that
                // do not adjust the readeahead level

                if ( read_command_again->readaheadpolicy==READAHEAD_POLICY_PIECE ) {

                    if ( read_command_again->startsector + READAHEAD_POLICY_PIECE_SECTORS > read_command_again->endsector ) {

                        read_command_again->endsector = read_command_again->startsector + READAHEAD_POLICY_PIECE_SECTORS;

                    }

                } else if ( read_command_again->readaheadpolicy==READAHEAD_POLICY_WHOLE ) {

                    if ( read_command_again->startsector + READAHEAD_POLICY_WHOLE_SECTORS > read_command_again->endsector ) {

                        read_command_again->endsector = read_command_again->startsector + READAHEAD_POLICY_WHOLE_SECTORS;

                    }

                }

            }

        }


        if ( read_command_again ) {

            // do not read past last sector for this track

            if ( read_command_again->endsector > audio_track->lastsector ) {

                read_command_again->endsector = audio_track->lastsector;

            }

            logoutput2("cdrom reader: sending a read command (%i - %i) again", read_command_again->startsector, read_command_again->endsector);

            add_read_command_to_queue(read_command_again);

        }


        if (foundincache) {

            //
            // signal and loop
            //

            if ( read_command->read_call ) {

                // notify waiting clients ..... of course only when there is one

                notify_waiting_clients(read_command->read_call, read_command->startsector, read_command->endsector);

            }

            free(read_command);
	    read_command=NULL;

            continue;

        }

        // correction and readahead done
        // ready to process read_command

	nrsectors = read_command->endsector - read_command->startsector + 1;

	if ( nrsectors <= 0 ) {

	    // invalid 

	    logoutput2("invalid block,nrsectors %i serious io error", nrsectors);
	    free(read_command);
	    read_command=NULL;
	    continue;

	}

        // does this work..???
        // mail on list.....

	device_resource=resource->parent;
	cdrom=(struct local_cdrom_struct *) device_resource->data;

        if ( cdio_cddap_speed_set((cdrom_drive_t *) cdrom->media.audio.cdda, -1) ) {

	    logoutput("setting cdrom to full speed failed...");

        } else {

	    logoutput("cdrom set to full speed...");

        }

        // the read of the cdrom goes in batches with size probably much smaller than the size requested
        // (batch size 20110920: 25 sectors)
        // but because it's not know here how much sectors are read in one batch (and how to change that)
        // we take the "overall" size of the buffer
        // and copy the sectors read to another buffer with the right size

        size_t size=nrsectors * CD_FRAMESIZE_RAW;

        createbuffer:

	buffer=malloc(size);

	if ( ! buffer ) {

	    // maybe retry here in case of errors

	    logoutput("error!! cannot create buffer to read cdrom.....ioerrors will be result...");
	    continue;

	}

	tries1=0;
	nrstartsector=read_command->startsector;
	nrsectorsread=0;
	nrtotalsectorsread=0;

	logoutput2("cdromreader: about to read %i sectors from sector %i", nrsectors, nrstartsector);

	readfromcd:

        // clear the buffer

        memset(buffer, '\0', size);
	nrsectorsread=cdio_cddap_read((cdrom_drive_t *) cdrom->media.audio.cdda, buffer, nrstartsector, nrsectors - nrtotalsectorsread);

        if ( nrsectorsread<0 ) {

            // handle error here

            logoutput2("cdromreader: error %i reading cd", nrsectorsread);

            tries1++;

            if ( tries1>4 ) {

                // howto report back to the original caller there is an error
                //
                // just for now do nothing to report back
                //
                // just leave it for the original caller (a cdfs_read call!) to expire and leave it there
                //
                // for an incident this is ok, but for serious error, like the cdrom is not readable
                // anymore the reading should be stopped in an earlier stage than here
                // 

	        free(read_command);
		read_command=NULL;
	        logoutput("error!! serious errors (%i) reading the cd", nrsectorsread);
	        free(buffer);
	        continue;

            }

            goto readfromcd;

        } else {


            // send the bytes to the cache

            if ( nrtotalsectorsread+nrsectorsread > nrsectors ) nrsectorsread=nrsectors-nrtotalsectorsread;
            tries2=0;

            //
            // create the buffer read, it's best to copy this to another buffer cause the writing to the cache
            // might take longer than the reading of the next buffer, overwriting existing read result
            // maybe this is nonsense but to be safe
            //

            createbufferread:

            buffread=malloc(nrsectorsread * CD_FRAMESIZE_RAW);

            if ( ! buffread ) {

                tries2++;

                if ( tries2>4 ) {

                    // same as above
                    // no way yet to report back
                    //
                    //

                    free(read_command);
		    read_command=NULL;
                    logoutput("error!! serious errors creating buffer reading the cd");
                    free(buffer);
                    continue;

                }

                goto createbufferread;

            }

            // copy the bytes just read in the cdrom read buffer (size: nrsectors) to the 
            // result buffer (size: nrsectorsread)

            memcpy(buffread, buffer, nrsectorsread * CD_FRAMESIZE_RAW);
            nreturn=send_read_result_to_cache(read_command->read_call, resource, nrstartsector, buffread, nrsectorsread);

            if ( nreturn<0 ) {

                free(read_command);
		read_command=NULL;
                logoutput("error!! serious errors creating buffer reading the cd");
                free(buffread);
                free(buffer);

                continue;

            }

            // update counters

	    nrtotalsectorsread+=nrsectorsread;
	    nrstartsector+=nrsectorsread;

	    logoutput2("cdromreader: %i sectors read, total so far: %i, %i requested)", nrsectorsread, nrtotalsectorsread, nrsectors);

            if ( nrtotalsectorsread>=nrsectors ) {

                // ready: continue
                // note it's not necessary to free the buffread, that's freed when it's written to the cache

                free(read_command);
		read_command=NULL;
                free(buffer);

                continue;

            }

            goto readfromcd;

	}

    }

    pthread_mutex_destroy(&queue_lockmutex);
    pthread_cond_destroy(&queue_lockcond);

    return NULL;

}
static void
CDDAReader_set_speed_device(cdio_CDDAReader *self, int new_speed)
{
    cdio_cddap_speed_set(self->_.drive.drive, new_speed);
}
Beispiel #5
0
static int cdpa_set_speed(rnc_dev_t *dev, int speed)
{
    cdpa_t *cdpa = dev->data;

    return cdio_cddap_speed_set(cdpa->cdda, speed);
}