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; }
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); }
static int cdpa_set_speed(rnc_dev_t *dev, int speed) { cdpa_t *cdpa = dev->data; return cdio_cddap_speed_set(cdpa->cdda, speed); }